From: <sag...@us...> - 2012-04-27 20:05:33
|
Revision: 1255 http://modplug.svn.sourceforge.net/modplug/?rev=1255&view=rev Author: saga-games Date: 2012-04-27 20:05:26 +0000 (Fri, 27 Apr 2012) Log Message: ----------- [Fix] Some small errors in S3M saver. [Imp] Default global volume is now written to pattern when converting to XM and is detected as an MPT extension in "Detect MPT hacks". [Ref] Smaller stuff. Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_gen.cpp trunk/OpenMPT/mptrack/MPTHacks.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/ModConvert.h trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Moddoc.h trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/Moptions.cpp trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp Modified: trunk/OpenMPT/mptrack/Ctrl_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_gen.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/Ctrl_gen.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -230,14 +230,15 @@ const BOOL bIsNotMOD = (m_pSndFile->GetType() != MOD_TYPE_MOD); const BOOL bIsNotMOD_S3M = ((bIsNotMOD) && (m_pSndFile->GetType() != MOD_TYPE_S3M)); + const BOOL bIsNotMOD_XM = ((bIsNotMOD) && (m_pSndFile->GetType() != MOD_TYPE_XM)); m_EditTempo.EnableWindow(bIsNotMOD); m_SpinTempo.EnableWindow(bIsNotMOD); m_SliderTempo.EnableWindow(bIsNotMOD); m_EditSpeed.EnableWindow(bIsNotMOD); m_SpinSpeed.EnableWindow(bIsNotMOD); - m_SliderGlobalVol.EnableWindow(bIsNotMOD); - m_EditGlobalVol.EnableWindow(bIsNotMOD); - m_SpinGlobalVol.EnableWindow(bIsNotMOD); + m_SliderGlobalVol.EnableWindow(bIsNotMOD_XM); + m_EditGlobalVol.EnableWindow(bIsNotMOD_XM); + m_SpinGlobalVol.EnableWindow(bIsNotMOD_XM); m_EditSamplePA.EnableWindow(bIsNotMOD); m_SpinSamplePA.EnableWindow(bIsNotMOD); //m_SliderSamplePreAmp.EnableWindow(bIsNotMOD); Modified: trunk/OpenMPT/mptrack/MPTHacks.cpp =================================================================== --- trunk/OpenMPT/mptrack/MPTHacks.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/MPTHacks.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -64,7 +64,7 @@ } } else if(type == MOD_TYPE_IT) // ModPlug IT extensions { - if((m.command == CMD_S3MCMDEX) && ((m.param >> 4) == 0x09) && (m.param != 0x91)) + if((m.command == CMD_S3MCMDEX) && ((m.param & 0xF0) == 0x90) && (m.param != 0x91)) { *foundHacks = true; if(autofix) @@ -220,6 +220,17 @@ } } + // Global volume + if(m_SndFile.GetType() == MOD_TYPE_XM && m_SndFile.m_nDefaultGlobalVolume != MAX_GLOBAL_VOLUME) + { + foundHacks = true; + AddToLog("XM format does not support default global volume"); + if(autofix) + { + GlobalVolumeToPattern(); + } + } + // Pattern count if(m_SndFile.Patterns.GetNumPatterns() > originalSpecs->patternsMax) { Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -85,7 +85,7 @@ const MODTYPE nOldType = m_SndFile.GetType(); - if (nNewType == nOldType && nNewType == MOD_TYPE_IT) + if(nNewType == nOldType && nNewType == MOD_TYPE_IT) { // Even if m_nType doesn't change, we might need to change extension in itp<->it case. // This is because ITP is a HACK and doesn't genuinely change m_nType, @@ -222,7 +222,7 @@ m->param = cEffectMemory[channel][m->command]; else cEffectMemory[channel][m->command] = m->param; - break; + break; } } @@ -498,6 +498,15 @@ { ConvertSamplesToInstruments(); } + + // XM has no global volume + if(newTypeIsXM && m_SndFile.m_nDefaultGlobalVolume != MAX_GLOBAL_VOLUME) + { + if(!GlobalVolumeToPattern()) + { + CHANGEMODTYPE_WARNING(wGlobalVolumeNotSupported); + } + } // Pattern warnings CHAR s[64]; @@ -530,6 +539,7 @@ CHANGEMODTYPE_CHECK(wEditHistory, "Edit history will not be saved in the new format.\n"); CHANGEMODTYPE_CHECK(wMixmode, "Consider setting the mix levels to \"Compatible\" in the song properties when working with legacy formats.\n"); CHANGEMODTYPE_CHECK(wCompatibilityMode, "Consider enabling the \"compatible playback\" option in the song properties to increase compatiblity with other players.\n"); + CHANGEMODTYPE_CHECK(wGlobalVolumeNotSupported, "Default global volume is not supported by the new format.\n"); SetModified(); GetPatternUndo().ClearUndo(); Modified: trunk/OpenMPT/mptrack/ModConvert.h =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.h 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/ModConvert.h 2012-04-27 20:05:26 UTC (rev 1255) @@ -35,5 +35,6 @@ wMixmode, wCompatibilityMode, wPitchToTempoLock, + wGlobalVolumeNotSupported, wNumWarnings }; Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -873,8 +873,8 @@ } -UINT CModDoc::GetPlaybackMidiChannel(const ModInstrument *pIns, CHANNELINDEX nChn) const -//-------------------------------------------------------------------------------------- +uint8 CModDoc::GetPlaybackMidiChannel(const ModInstrument *pIns, CHANNELINDEX nChn) const +//--------------------------------------------------------------------------------------- { if(pIns->nMidiChannel == MidiMappedChannel) { @@ -1025,7 +1025,7 @@ if ((!nPlugin || nPlugin > MAX_MIXPLUGINS) && nCurrentChn != CHANNELINDEX_INVALID) nPlugin = m_SndFile.ChnSettings[nCurrentChn].nMixPlugin; // Then try Channel VST - if ((nPlugin) && (nPlugin <= MAX_MIXPLUGINS)) + if ((nPlugin) && (nPlugin <= MAX_MIXPLUGINS)) { IMixPlugin *pPlugin = m_SndFile.m_MixPlugins[nPlugin - 1].pMixPlugin; Modified: trunk/OpenMPT/mptrack/Moddoc.h =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.h 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/Moddoc.h 2012-04-27 20:05:26 UTC (rev 1255) @@ -113,12 +113,15 @@ ///////////////////////////////////////////////////////////////////////// // Split Keyboard Settings (pattern editor) -#define SPLIT_OCTAVE_RANGE 9 - //========================== struct SplitKeyboardSettings //========================== { + enum + { + splitOctaveRange = 9, + }; + bool IsSplitActive() const { return (octaveLink && (octaveModifier != 0)) || (splitInstrument > 0) || (splitVolume != 0); } ModCommand::NOTE splitNote; ModCommand::INSTR splitInstrument; @@ -296,7 +299,9 @@ void LearnMacro(int macro, long param); void SetElapsedTime(ORDERINDEX nOrd, ROWINDEX nRow); + // Global settings to pattern effect conversion bool RestartPosToPattern(); + bool GlobalVolumeToPattern(); bool HasMPTHacks(const bool autofix = false); @@ -346,7 +351,7 @@ virtual void SetModifiedFlag(BOOL bModified=TRUE); //}}AFX_VIRTUAL - UINT GetPlaybackMidiChannel(const ModInstrument *pIns, CHANNELINDEX nChn) const; + uint8 GetPlaybackMidiChannel(const ModInstrument *pIns, CHANNELINDEX nChn) const; // Implementation Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -919,3 +919,25 @@ m_SndFile.m_nRestartPos = 0; return result; } + + +// Convert module's default global volume to a pattern command. +bool CModDoc::GlobalVolumeToPattern() +//----------------------------------- +{ + bool result = false; + if(m_SndFile.GetModSpecifications().HasCommand(CMD_GLOBALVOLUME)) + { + for(ORDERINDEX i = 0; i < m_SndFile.Order.GetLength(); i++) + { + if(m_SndFile.TryWriteEffect(m_SndFile.Order[i], 0, CMD_GLOBALVOLUME, m_SndFile.m_nDefaultGlobalVolume * 64 / MAX_GLOBAL_VOLUME, false, CHANNELINDEX_INVALID, false, weTryNextRow)) + { + result = true; + break; + } + } + } + + m_SndFile.m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; + return result; +} Modified: trunk/OpenMPT/mptrack/Moptions.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moptions.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/Moptions.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -20,15 +20,13 @@ ////////////////////////////////////////////////////////////// // COptionsColors -typedef struct MPTCOLORDEF +static const struct ColorDescriptions { - LPCSTR pszName; - int nPreview; - UINT nColNdx1, nColNdx2, nColNdx3; - LPCSTR pszTxt1, pszTxt2, pszTxt3; -} MPTCOLORDEF; - -static MPTCOLORDEF gColorDefs[] = + char *name; + int previewImage; + uint32 colorIndex1, colorIndex2, colorIndex3; + char *descText1, *descText2, *descText3; +} colorDefs[] = { {"Pattern Editor", 0, MODCOLOR_BACKNORMAL, MODCOLOR_TEXTNORMAL, MODCOLOR_BACKHILIGHT, "Background:", "Foreground:", "Highlighted:"}, {"Active Row", 0, MODCOLOR_BACKCURROW, MODCOLOR_TEXTCURROW, 0, "Background:", "Foreground:", NULL}, @@ -92,9 +90,9 @@ CPropertyPage::OnInitDialog(); m_pPreviewDib = LoadDib(MAKEINTRESOURCE(IDB_COLORSETUP)); MemCopy(CustomColors, CMainFrame::GetSettings().rgbCustomColors); - for (UINT i = 0; i < CountOf(gColorDefs); i++) + for (UINT i = 0; i < CountOf(colorDefs); i++) { - m_ComboItem.SetItemData(m_ComboItem.AddString(gColorDefs[i].pszName), i); + m_ComboItem.SetItemData(m_ComboItem.AddString(colorDefs[i].name), i); } m_ComboItem.SetCurSel(0); m_BtnPreview.SetWindowPos(NULL, 0,0, PREVIEWBMP_WIDTH*2+2, PREVIEWBMP_HEIGHT*2+2, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); @@ -161,9 +159,9 @@ int nColor = -1; switch(nIdCtl) { - case IDC_BUTTON1: nColor = gColorDefs[m_nColorItem].nColNdx1; break; - case IDC_BUTTON2: nColor = gColorDefs[m_nColorItem].nColNdx2; break; - case IDC_BUTTON3: nColor = gColorDefs[m_nColorItem].nColNdx3; break; + case IDC_BUTTON1: nColor = colorDefs[m_nColorItem].colorIndex1; break; + case IDC_BUTTON2: nColor = colorDefs[m_nColorItem].colorIndex2; break; + case IDC_BUTTON3: nColor = colorDefs[m_nColorItem].colorIndex3; break; } if (!lpdis) return; if (nColor >= 0) @@ -193,7 +191,7 @@ } else if ((nIdCtl == IDC_BUTTON4) && (m_pPreviewDib)) { - int y = gColorDefs[m_nColorItem].nPreview; + int y = colorDefs[m_nColorItem].previewImage; RGBQUAD *p = m_pPreviewDib->bmiColors; if (IsDlgButtonChecked(IDC_CHECK2)) { @@ -302,21 +300,21 @@ void COptionsColors::OnSelectColor1() //----------------------------------- { - SelectColor(&CustomColors[gColorDefs[m_nColorItem].nColNdx1]); + SelectColor(&CustomColors[colorDefs[m_nColorItem].colorIndex1]); } void COptionsColors::OnSelectColor2() //----------------------------------- { - SelectColor(&CustomColors[gColorDefs[m_nColorItem].nColNdx2]); + SelectColor(&CustomColors[colorDefs[m_nColorItem].colorIndex2]); } void COptionsColors::OnSelectColor3() //----------------------------------- { - SelectColor(&CustomColors[gColorDefs[m_nColorItem].nColNdx3]); + SelectColor(&CustomColors[colorDefs[m_nColorItem].colorIndex3]); } @@ -340,11 +338,11 @@ void COptionsColors::OnUpdateDialog() //----------------------------------- { - MPTCOLORDEF *p = &gColorDefs[m_nColorItem]; - if (p->pszTxt1) m_TxtColor1.SetWindowText(p->pszTxt1); - if (p->pszTxt2) + const ColorDescriptions *p = &colorDefs[m_nColorItem]; + if (p->descText1) m_TxtColor1.SetWindowText(p->descText1); + if (p->descText2) { - m_TxtColor2.SetWindowText(p->pszTxt2); + m_TxtColor2.SetWindowText(p->descText2); m_TxtColor2.ShowWindow(SW_SHOW); m_BtnColor2.ShowWindow(SW_SHOW); m_BtnColor2.InvalidateRect(NULL, FALSE); @@ -353,9 +351,9 @@ m_TxtColor2.ShowWindow(SW_HIDE); m_BtnColor2.ShowWindow(SW_HIDE); } - if (p->pszTxt3) + if (p->descText3) { - m_TxtColor3.SetWindowText(p->pszTxt3); + m_TxtColor3.SetWindowText(p->descText3); m_TxtColor3.ShowWindow(SW_SHOW); m_BtnColor3.ShowWindow(SW_SHOW); m_BtnColor3.InvalidateRect(NULL, FALSE); @@ -538,24 +536,22 @@ END_MESSAGE_MAP() -struct OPTGENDESC +static const struct GeneralOptionsDescriptions { - DWORD dwFlagID; - LPCSTR pszListName, pszDescription; -}; - -static OPTGENDESC gOptGenDesc[] = + uint32 flag; + char *name, *description; +} generalOptionsList[] = { {PATTERN_PLAYNEWNOTE, "Play new notes while recording", "When this option is enabled, notes entered in the pattern editor will always be played (If not checked, notes won't be played in record mode)."}, {PATTERN_PLAYEDITROW, "Play whole row while recording", "When this option is enabled, all notes on the current row are played when entering notes in the pattern editor."}, - {PATTERN_CENTERROW, "Always center active row", "Turn on this option to have the active row always centered in the pattern editor (requires \"Always center active row\")."}, + {PATTERN_CENTERROW, "Always center active row", "Turn on this option to have the active row always centered in the pattern editor."}, {PATTERN_LARGECOMMENTS, "Use large font for comments", "With this option enabled, the song message editor will use a larger font."}, {PATTERN_HEXDISPLAY, "Display rows in hex", "With this option enabled, row numbers and sequence numbers will be displayed in hexadecimal."}, {PATTERN_WRAP, "Cursor wrap in pattern editor", "When this option is active, going past the end of a pattern row or channel will move the cursor to the beginning. When \"Continuous scroll\"-option is enabled, row wrap is disabled."}, {PATTERN_CREATEBACKUP, "Create backup files (*.bak)", "When this option is active, saving a file will create a backup copy of the original."}, - {PATTERN_DRAGNDROPEDIT, "Drag and Drop Editing", "Enable moving a selection in the pattern editor (copying if pressing shift while dragging)\n"}, + {PATTERN_DRAGNDROPEDIT, "Drag and Drop Editing", "Enable moving a selection in the pattern editor (copying if pressing shift while dragging)"}, {PATTERN_FLATBUTTONS, "Flat Buttons", "Use flat buttons in toolbars"}, - {PATTERN_SINGLEEXPAND, "Single click to expand tree", "Single-clicking in the left tree view will expand a branch"}, + {PATTERN_SINGLEEXPAND, "Single click to expand tree", "Single-clicking in the left tree view will expand a node."}, {PATTERN_MUTECHNMODE, "Ignored muted channels", "Notes will not be played on muted channels (unmuting will only start on a new note)."}, {PATTERN_NOEXTRALOUD, "No loud sample preview", "Disable loud playback of samples in the sample/instrument editor. Sample volume depends on the sample volume slider on the general tab when activated (if disabled, a sample volume of 256 is used)."}, {PATTERN_SHOWPREVIOUS, "Show Prev/Next patterns", "Displays grayed-out version of the previous/next patterns in the pattern editor. Does not work if \"always center active row\" is disabled."}, @@ -563,10 +559,10 @@ {PATTERN_KBDNOTEOFF, "Record note off", "Record note off when a key is released on the PC keyboard."}, {PATTERN_FOLLOWSONGOFF, "Follow song off by default", "Ensure follow song is off when opening or starting a new song."}, {PATTERN_MIDIRECORD, "MIDI record", "Enable MIDI in record by default."}, - {PATTERN_OLDCTXMENUSTYLE, "Old style pattern context menu", "Check this option to hide unavailable items in the pattern editor context menu. Uncheck to grey-out unavailable items instead."}, + {PATTERN_OLDCTXMENUSTYLE, "Old style pattern context menu", "Check this option to hide unavailable items in the pattern editor context menu. Uncheck to grey-out unavailable items instead."}, {PATTERN_SYNCMUTE, "Maintain sample sync on mute", "Samples continue to be processed when channels are muted (like in IT2 and FT2)"}, {PATTERN_AUTODELAY, "Automatic delay commands", "Automatically insert appropriate note-delay commands when recording notes during live playback."}, - {PATTERN_NOTEFADE, "Note fade on key up", "Enable to fade / stop notes on key up in pattern tab." }, + {PATTERN_NOTEFADE, "Note fade on key up", "Enable to fade / stop notes on key up in pattern tab."}, {PATTERN_OVERFLOWPASTE, "Overflow paste mode", "Wrap pasted pattern data into next pattern. This is useful for creating echo channels."}, {PATTERN_RESETCHANNELS, "Reset channels on loop", "If enabled, channels will be reset to their initial state when song looping is enabled.\nNote: This does not affect manual song loops (i.e. triggered by pattern commands) and is recommended to be enabled."}, {PATTERN_LIVEUPDATETREE,"Update sample status in tree", "If enabled, active samples and instruments will be indicated by a different icon in the treeview."}, @@ -592,15 +588,15 @@ CHAR sname[32], s[256]; CPropertyPage::OnInitDialog(); - for (UINT i = 0; i < CountOf(gOptGenDesc); i++) + for(size_t i = 0; i < CountOf(generalOptionsList); i++) { wsprintf(sname, "Setup.Gen.Opt%d.Name", i + 1); if ((theApp.GetLocalizedString(sname, s, sizeof(s))) && (s[0])) m_CheckList.AddString(s); else - m_CheckList.AddString(gOptGenDesc[i].pszListName); + m_CheckList.AddString(generalOptionsList[i].name); - const int check = (CMainFrame::GetSettings().m_dwPatternSetup & gOptGenDesc[i].dwFlagID) != 0 ? BST_CHECKED : BST_UNCHECKED; + const int check = (CMainFrame::GetSettings().m_dwPatternSetup & generalOptionsList[i].flag) != 0 ? BST_CHECKED : BST_UNCHECKED; m_CheckList.SetCheck(i, check); } m_CheckList.SetCurSel(0); @@ -628,12 +624,12 @@ GetDlgItemText(IDC_OPTIONS_DIR_VSTS, szVstDir, _MAX_PATH); GetDlgItemText(IDC_OPTIONS_DIR_VSTPRESETS, szPresetDir, _MAX_PATH); - for (UINT i = 0; i < CountOf(gOptGenDesc); i++) + for(size_t i = 0; i < CountOf(generalOptionsList); i++) { const bool check = (m_CheckList.GetCheck(i) != BST_UNCHECKED); - if(check) CMainFrame::GetSettings().m_dwPatternSetup |= gOptGenDesc[i].dwFlagID; - else CMainFrame::GetSettings().m_dwPatternSetup &= ~gOptGenDesc[i].dwFlagID; + if(check) CMainFrame::GetSettings().m_dwPatternSetup |= generalOptionsList[i].flag; + else CMainFrame::GetSettings().m_dwPatternSetup &= ~generalOptionsList[i].flag; } CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); @@ -683,9 +679,9 @@ CHAR sname[32], s[256]; LPCSTR pszDesc = NULL; const int sel = m_CheckList.GetCurSel(); - if ((sel >= 0) && (sel < CountOf(gOptGenDesc))) + if ((sel >= 0) && (sel < CountOf(generalOptionsList))) { - pszDesc = gOptGenDesc[sel].pszDescription; + pszDesc = generalOptionsList[sel].description; wsprintf(sname, "Setup.Gen.Opt%d.Desc", sel+1); if ((theApp.GetLocalizedString(sname, s, sizeof(s))) && (s[0])) pszDesc = s; } Modified: trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -1505,14 +1505,14 @@ m_CbnSplitNote.SetCurSel(m_Settings.splitNote - (m_pSndFile->GetModSpecifications().noteMin - NOTE_MIN)); // Octave modifier - for(int i = -SPLIT_OCTAVE_RANGE; i < SPLIT_OCTAVE_RANGE + 1; i++) + for(int i = -SplitKeyboardSettings::splitOctaveRange; i < SplitKeyboardSettings::splitOctaveRange + 1; i++) { wsprintf(s, i < 0 ? "Octave -%d" : i > 0 ? "Octave +%d" : "No Change", abs(i)); int n = m_CbnOctaveModifier.AddString(s); m_CbnOctaveModifier.SetItemData(n, i); } - m_CbnOctaveModifier.SetCurSel(m_Settings.octaveModifier + SPLIT_OCTAVE_RANGE); + m_CbnOctaveModifier.SetCurSel(m_Settings.octaveModifier + SplitKeyboardSettings::splitOctaveRange); CheckDlgButton(IDC_PATTERN_OCTAVELINK, (m_Settings.octaveLink && m_Settings.octaveModifier != 0) ? MF_CHECKED : MF_UNCHECKED); // Volume @@ -1565,7 +1565,7 @@ CDialog::OnOK(); m_Settings.splitNote = static_cast<ModCommand::NOTE>(m_CbnSplitNote.GetCurSel() + (m_pSndFile->GetModSpecifications().noteMin - NOTE_MIN)); - m_Settings.octaveModifier = m_CbnOctaveModifier.GetCurSel() - SPLIT_OCTAVE_RANGE; + m_Settings.octaveModifier = m_CbnOctaveModifier.GetCurSel() - SplitKeyboardSettings::splitOctaveRange; m_Settings.octaveLink = (IsDlgButtonChecked(IDC_PATTERN_OCTAVELINK) == TRUE); m_Settings.splitVolume = static_cast<ModCommand::VOL>(m_CbnSplitVolume.GetCurSel()); m_Settings.splitInstrument = static_cast<ModCommand::INSTR>(m_CbnSplitInstrument.GetItemData(m_CbnSplitInstrument.GetCurSel())); Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-04-23 15:28:34 UTC (rev 1254) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-04-27 20:05:26 UTC (rev 1255) @@ -114,22 +114,16 @@ } else command = 0; break; case CMD_MODCMDEX: - command = 'S'; - switch(param & 0xF0) { - 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; - case 0x40: param = (param & 0x0F) | 0x30; break; - case 0x50: param = (param & 0x0F) | 0x20; break; - 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 = 0; break; - case 0xB0: if(param & 0x0F) { command = 'D'; param |= 0xF0; } else command = 0; break; + ModCommand m; + m.command = CMD_MODCMDEX; + m.param = param; + m.ExtendedMODtoS3MEffect(); + command = m.command; + param = m.param; + S3MSaveConvert(command, param, toIT, compatibilityExport); } - break; + return; // Chars under 0x40 don't save properly, so map : to ] and # to [. case CMD_DELAYCUT: if(compatibilityExport || !toIT) @@ -279,7 +273,7 @@ uint32 c5speed; // Middle-C frequency char reserved2[12]; // Reserved + Internal ST3 stuff char name[28]; // Sample name - uint32 magic; // "SCRS" magic bytes + uint32 magic; // "SCRS" magic bytes ("SCRI" for Adlib instruments) // Convert all multi-byte numeric values to current platform's endianness or vice versa. void ConvertEndianness() @@ -518,11 +512,11 @@ } else { m_nChannels = i + 1; - ChnSettings[i].nPan = (fileHeader.channels[i] & 8) ? 192 : 64; + ChnSettings[i].nPan = (fileHeader.channels[i] & 8) ? 192 : 64; // 200 : 56 if(fileHeader.channels[i] & 0x80) { ChnSettings[i].dwFlags = CHN_MUTE; - // Detect Adlib channels here: + // Detect Adlib channels here (except for OpenMPT 1.19 and older, which would write wrong channel types for PCM channels 16-32): // c = channels[i] ^ 0x80; // if(c >= 16 && c < 32) adlibChannel = true; } @@ -799,7 +793,7 @@ // Version info following: ST3.20 = 0x1320 // Most significant nibble = Tracker ID, see S3MFileHeader::S3MTrackerVersions // Following: One nibble = Major version, one byte = Minor version (hex) - fileHeader.cwtv = S3MFileHeader::trackerMask | static_cast<uint16>((MptVersion::num >> 16) & S3MFileHeader::versionMask); + fileHeader.cwtv = S3MFileHeader::trkOpenMPT | static_cast<uint16>((MptVersion::num >> 16) & S3MFileHeader::versionMask); fileHeader.formatVersion = S3MFileHeader::newVersion; fileHeader.magic = S3MFileHeader::idSCRM; @@ -816,8 +810,9 @@ { if(chn < GetNumChannels()) { - uint8 ch = (chn & 0x0F) >> 1; - ch = (chn & 0x10) | ((chn & 1) ? 8 + ch : ch); + // ST3 only supports 16 PCM channels, so if channels 17-32 are used, + // they must be mapped to the same "internal channels" as channels 1-16. + uint8 ch = ((chn << 3) | (chn >> 1)) & 0x0F; if((ChnSettings[chn].dwFlags & CHN_MUTE) != 0) { ch |= 0x80; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-04 20:26:20
|
Revision: 1261 http://modplug.svn.sourceforge.net/modplug/?rev=1261&view=rev Author: saga-games Date: 2012-05-04 20:26:13 +0000 (Fri, 04 May 2012) Log Message: ----------- [Mod] Updated VS2008 project to use the correct exception handling settings. [Mod] Added OpenMPT 1.20 release notes Modified Paths: -------------- trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/packageTemplate/ReleaseNotesImages/general/modplug.png Added Paths: ----------- trunk/OpenMPT/packageTemplate/OMPT_1.20_ReleaseNotes.html trunk/OpenMPT/packageTemplate/ReleaseNotesImages/1.20/ trunk/OpenMPT/packageTemplate/ReleaseNotesImages/1.20/modified_files.png Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-05-04 15:35:58 UTC (rev 1260) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-05-04 20:26:13 UTC (rev 1261) @@ -47,11 +47,11 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/EHsc" Optimization="0" 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" + ExceptionHandling="2" BasicRuntimeChecks="3" RuntimeLibrary="3" BufferSecurityCheck="true" @@ -154,12 +154,12 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/EHsc /O2" Optimization="2" InlineFunctionExpansion="2" 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" + ExceptionHandling="2" RuntimeLibrary="0" BufferSecurityCheck="true" EnableFunctionLevelLinking="false" @@ -257,10 +257,6 @@ > </File> <File - RelativePath=".\ChannelManagerDlg.cpp" - > - </File> - <File RelativePath=".\ChildFrm.cpp" > </File> @@ -269,10 +265,6 @@ > </File> <File - RelativePath=".\CloseMainDialog.cpp" - > - </File> - <File RelativePath=".\ColourEdit.cpp" > </File> @@ -313,10 +305,6 @@ > </File> <File - RelativePath=".\dlg_misc.cpp" - > - </File> - <File RelativePath="..\soundlib\dlsbank.cpp" > </File> @@ -325,10 +313,6 @@ > </File> <File - RelativePath=".\EffectInfo.cpp" - > - </File> - <File RelativePath=".\EffectVis.cpp" > </File> @@ -365,7 +349,7 @@ > </File> <File - RelativePath=".\KeyConfigDlg.cpp" + RelativePath="..\soundlib\plugins\JBridge.cpp" > </File> <File @@ -385,18 +369,10 @@ > </File> <File - RelativePath=".\MIDIMacroDialog.cpp" - > - </File> - <File RelativePath="..\soundlib\MIDIMacros.cpp" > </File> <File - RelativePath=".\MIDIMappingDialog.cpp" - > - </File> - <File RelativePath=".\MIDIMapping.cpp" > </File> @@ -433,14 +409,6 @@ > </File> <File - RelativePath="..\soundlib\ModInstrument.cpp" - > - </File> - <File - RelativePath="..\soundlib\ModSample.cpp" - > - </File> - <File RelativePath=".\ModConvert.cpp" > </File> @@ -453,26 +421,22 @@ > </File> <File - RelativePath="..\soundlib\ModSequence.cpp" + RelativePath="..\soundlib\ModInstrument.cpp" > </File> <File - RelativePath="..\soundlib\modsmp_ctrl.cpp" + RelativePath="..\soundlib\ModSample.cpp" > </File> <File - RelativePath=".\Moptions.cpp" + RelativePath="..\soundlib\ModSequence.cpp" > </File> <File - RelativePath=".\MoveFXSlotDialog.cpp" + RelativePath="..\soundlib\modsmp_ctrl.cpp" > </File> <File - RelativePath=".\Mpdlgs.cpp" - > - </File> - <File RelativePath=".\mpt_midi.cpp" > </File> @@ -501,22 +465,10 @@ > </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> @@ -525,30 +477,10 @@ > </File> <File - RelativePath="..\soundlib\XMTools.cpp" - > - </File> - <File - RelativePath="..\soundlib\plugins\JBridge.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> @@ -676,6 +608,10 @@ RelativePath="..\soundlib\WindowedFIR.cpp" > </File> + <File + RelativePath="..\soundlib\XMTools.cpp" + > + </File> <Filter Name="PatternRandomizer" > @@ -828,6 +764,74 @@ > </File> </Filter> + <Filter + Name="Dialogs" + > + <File + RelativePath=".\ChannelManagerDlg.cpp" + > + </File> + <File + RelativePath=".\CloseMainDialog.cpp" + > + </File> + <File + RelativePath=".\dlg_misc.cpp" + > + </File> + <File + RelativePath=".\EffectInfo.cpp" + > + </File> + <File + RelativePath=".\KeyConfigDlg.cpp" + > + </File> + <File + RelativePath=".\MIDIMacroDialog.cpp" + > + </File> + <File + RelativePath=".\MIDIMappingDialog.cpp" + > + </File> + <File + RelativePath=".\Moptions.cpp" + > + </File> + <File + RelativePath=".\MoveFXSlotDialog.cpp" + > + </File> + <File + RelativePath=".\Mpdlgs.cpp" + > + </File> + <File + RelativePath=".\PatternEditorDialogs.cpp" + > + </File> + <File + RelativePath=".\PatternGotoDialog.cpp" + > + </File> + <File + RelativePath=".\PSRatioCalc.cpp" + > + </File> + <File + RelativePath=".\SampleEditorDialogs.cpp" + > + </File> + <File + RelativePath=".\ScaleEnvPointsDlg.cpp" + > + </File> + <File + RelativePath=".\SelectPluginDialog.cpp" + > + </File> + </Filter> </Filter> <Filter Name="Resource Files" @@ -939,10 +943,6 @@ > </File> <File - RelativePath=".\ChannelManagerDlg.h" - > - </File> - <File RelativePath=".\ChildFrm.h" > </File> @@ -951,10 +951,6 @@ > </File> <File - RelativePath=".\CloseMainDialog.h" - > - </File> - <File RelativePath=".\ColourEdit.h" > </File> @@ -991,10 +987,6 @@ > </File> <File - RelativePath=".\dlg_misc.h" - > - </File> - <File RelativePath="..\Soundlib\Dlsbank.h" > </File> @@ -1003,10 +995,6 @@ > </File> <File - RelativePath=".\EffectVis.h" - > - </File> - <File RelativePath="..\soundlib\Endianness.h" > </File> @@ -1027,7 +1015,7 @@ > </File> <File - RelativePath=".\KeyConfigDlg.h" + RelativePath=".\soundlib\plugins\JBridge.h" > </File> <File @@ -1043,18 +1031,10 @@ > </File> <File - RelativePath=".\MIDIMacroDialog.h" - > - </File> - <File RelativePath=".\soundlib\MIDIMacros.h" > </File> <File - RelativePath=".\MIDIMappingDialog.h" - > - </File> - <File RelativePath=".\MIDIMapping.h" > </File> @@ -1083,19 +1063,19 @@ > </File> <File - RelativePath="..\soundlib\ModInstrument.h" + RelativePath=".\ModConvert.h" > </File> <File - RelativePath="..\soundlib\ModSample.h" + RelativePath=".\moddoc.h" > </File> <File - RelativePath=".\ModConvert.h" + RelativePath="..\soundlib\ModInstrument.h" > </File> <File - RelativePath=".\moddoc.h" + RelativePath="..\soundlib\ModSample.h" > </File> <File @@ -1107,18 +1087,6 @@ > </File> <File - RelativePath=".\Moptions.h" - > - </File> - <File - RelativePath=".\MoveFXSlotDialog.h" - > - </File> - <File - RelativePath=".\Mpdlgs.h" - > - </File> - <File RelativePath=".\mptrack.h" > </File> @@ -1139,22 +1107,10 @@ > </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\plugins\PluginEventQueue.h" > </File> @@ -1167,18 +1123,6 @@ > </File> <File - RelativePath=".\soundlib\plugins\JBridge.h" - > - </File> - <File - RelativePath=".\soundlib\RowVisitor.h" - > - </File> - <File - RelativePath=".\soundlib\XMTools.h" - > - </File> - <File RelativePath="..\common\Reporting.h" > </File> @@ -1187,7 +1131,7 @@ > </File> <File - RelativePath=".\SampleEditorDialogs.h" + RelativePath=".\soundlib\RowVisitor.h" > </File> <File @@ -1195,14 +1139,6 @@ > </File> <File - RelativePath=".\ScaleEnvPointsDlg.h" - > - </File> - <File - RelativePath=".\SelectPluginDialog.h" - > - </File> - <File RelativePath=".\serialization_utils.h" > </File> @@ -1302,6 +1238,10 @@ RelativePath="..\soundlib\WindowedFIR.h" > </File> + <File + RelativePath=".\soundlib\XMTools.h" + > + </File> <Filter Name="tuning" > @@ -1326,6 +1266,74 @@ > </File> </Filter> + <Filter + Name="Dialogs" + > + <File + RelativePath=".\ChannelManagerDlg.h" + > + </File> + <File + RelativePath=".\CloseMainDialog.h" + > + </File> + <File + RelativePath=".\dlg_misc.h" + > + </File> + <File + RelativePath=".\EffectVis.h" + > + </File> + <File + RelativePath=".\KeyConfigDlg.h" + > + </File> + <File + RelativePath=".\MIDIMacroDialog.h" + > + </File> + <File + RelativePath=".\MIDIMappingDialog.h" + > + </File> + <File + RelativePath=".\Moptions.h" + > + </File> + <File + RelativePath=".\MoveFXSlotDialog.h" + > + </File> + <File + RelativePath=".\Mpdlgs.h" + > + </File> + <File + RelativePath=".\PatternEditorDialogs.h" + > + </File> + <File + RelativePath=".\PatternGotoDialog.h" + > + </File> + <File + RelativePath=".\PSRatioCalc.h" + > + </File> + <File + RelativePath=".\SampleEditorDialogs.h" + > + </File> + <File + RelativePath=".\ScaleEnvPointsDlg.h" + > + </File> + <File + RelativePath=".\SelectPluginDialog.h" + > + </File> + </Filter> </Filter> <Filter Name="test" @@ -1343,11 +1351,11 @@ Name="Module Loaders" > <File - RelativePath="..\soundlib\ITTools.h" + RelativePath="..\soundlib\ITTools.cpp" > </File> <File - RelativePath="..\soundlib\ITTools.cpp" + RelativePath="..\soundlib\ITTools.h" > </File> <File Added: trunk/OpenMPT/packageTemplate/OMPT_1.20_ReleaseNotes.html =================================================================== --- trunk/OpenMPT/packageTemplate/OMPT_1.20_ReleaseNotes.html (rev 0) +++ trunk/OpenMPT/packageTemplate/OMPT_1.20_ReleaseNotes.html 2012-05-04 20:26:13 UTC (rev 1261) @@ -0,0 +1,170 @@ +<?xml version="1.0" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>OpenMPT 1.20 Release Notes</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <meta name="language" content="en" /> + <style type="text/css"> + * { font-family: Calibri, sans-serif; } + body + { + color: #222; + background: #eee; + font-size: 13pt; + margin: 0 0 1em 0; + padding: 0; + border: none; + } + + a { color: #b30; text-decoration: none; } + a:visited { color: #910; text-decoration: none; } + a:hover { text-decoration: underline; } + + .screenshots + { + float:right; + text-align:right; + } + + .screenshots img, h1 + { + border: 1px solid #ccc; + padding: 3px; + background: #f0f0f0; + margin: 0 0 3px 3px; + } + + p { margin: 0.5em 1em; padding: 0; } + + h1 + { + margin: 0 0 1em 0; + padding: 10px; + font-size: 24pt; + color: #444; + text-shadow: 1px 1px 1px #999; + background-image: linear-gradient(bottom, #ddd 20%, #eee 60%); + background-image: -o-linear-gradient(bottom, #ddd 20%, #eee 60%); + background-image: -moz-linear-gradient(bottom, #ddd 20%, #eee 60%); + background-image: -webkit-linear-gradient(bottom, #ddd 20%, #eee 60%); + background-image: -ms-linear-gradient(bottom, #ddd 20%, #eee 60%); + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.2, #ddd), color-stop(0.6, #eee)); + border-width: 0 0 1px 0; + } + + h1 img { vertical-align: middle; margin-right: 1em; } + + h2, h3, h4 + { + border: 1px solid #ccc; + border-width: 0 0 0 3em; + margin: 1em 0.5em; + padding: 0px 5px; + font-size: 18pt; + color: #333; + text-shadow: 1px 1px #fff; + } + + h3 { border-left-width: 2em; } + h4 { border-left-width: 1em; } + + li {list-style-type: none; padding: 0 0 0.5em 0; } + li:before { content: "» "; } + + li li { padding: 0; } + + /* use this for pattern data */ + pre + { + font-family: monospace; + display: inline; + color: #006; + } + + </style> + </head> + <body> + + <h1> + <img src="ReleaseNotesImages/general/modplug.png" width="81" height="80" alt="OpenMPT Logo" /> + OpenMPT 1.20 - Release Notes + </h1> + + <p> + OpenMPT has introduced a number of noteworthy new features since the last official release (version 1.19.04.00). + This document should give a rough overview about the greatest changes in OpenMPT 1.20. + </p> + + <h2>What's new?</h2> + + <h3>General</h3> + <div class="screenshots"> + <a href="ReleaseNotesImages/1.20/modified_files.png"><img src="ReleaseNotesImages/1.20/modified_files.png" width="240" height="148" alt="Modified files dialog" title="Modified files dialog (click to view big screenshot)" /></a> + </div> + <ul> + <li>OpenMPT 1.20 introduces a <strong>template system</strong> that can be used to quickly access often used plugin, pattern, sample and instrument combinations.</li> + <li>When closing OpenMPT, a single dialog with a <strong>list of unsaved files</strong> is now shown instead of one message boxes for each modified file.</li> + <li><strong>Crash recovery</strong>: When a crash is encountered, OpenMPT will try to save modified documents to a temporary location and close the audio device. The latter can especially help with ASIO drivers that become unusable after a program crash.</li> + <li><strong>MIDI CCs</strong> that are being received from an external MIDI device can now be mapped to pattern / sample / instrument editor shortcuts.</li> + <li>The <strong>treeview</strong> can now handle more than 32 open modules.</li> + <li>At last, OpenMPT comes with a <strong>manual</strong> again!</li> + </ul> + + <h3>Pattern Editor</h3> + <ul> + <li><strong>Adding and removing channels</strong> creates an undo point now instead of clearing the undo log.</li> + <li>There is now an option to <strong>select a channel</strong> by double-clicking a pattern cell.</li> + <li>Like in Impulse Tracker, it is now possible to show the <strong>default sample volume</strong> if there is no volume command next to a note.</li> + <li>OpenMPT can now recording incoming <strong>aftertouch MIDI messages</strong> to patterns as either volume commands or MIDI macros.</li> + </ul> + + <h3>Sample Editor</h3> + <ul> + <li>The new <strong>sample tuner</strong> can be used to tune samples to a given note.</li> + </ul> + + <h3>Macro System</h3> + <ul> + <li>The MIDI macro system has been rewritten completely and is now (hopefully) 99% compatible with IT's MIDI macros. Some macro letters have been changed / added, see the "macro help" button in the macro settings or the manual for more information.</li> + </ul> + + <h3>VST Plugins</h3> + <ul> + <li>OpenMPT comes with its own <strong>MIDI Input / Output plugin</strong> that can be used to route MIDI event from external devices to other plugins or to send MIDI events to your MIDI gear. + <li>Plugins can now <strong>route MIDI events</strong> to follow-up plugins. This can be useful for LFO, arpeggiator or groove plugins.</li> + <li>Searching for multiple <strong>unknown plugins</strong> will now open only one browser window.</li> + <li>Some <strong>multi-output plugins</strong> like Kontakt (64 channels version) won't crash anymore.</li> + <li>Built-in support for <strong>jBridge</strong> to provide support for 64-Bit plugins and other plugins that won't load in OpenMPT.</li> + <li>Exception handling for crashed plugins does finally work again, so the <strong>overall stability</strong> of OpenMPT as a VST host has increased. Note that a few plugins don't seem to like exception handling and might crash now.</li> + </ul> + + <h3>There's more...</h3> + <p> + For a detailed description of what has changed, check <a href="History.txt">History.txt</a>. + </p> + + <h2>Known Issues</h2> + <p> + <i>This list has mostly been copied over from the old OpenMPT 1.17 RC2 release notes, so this not very comprehensive... :-)</i> + </p> + <ul> + <li>Far from perfect VST support (no buses for audio / MIDI routing, only a few tracker effects are supported, etc...)</li> + <li>Previewing samples from the treeview's file browser stops the playing module.</li> + <li>Cannot preview instruments directly from the MIDI Library in the tree view.</li> + <li>Excessive performance drop when dragging over the graphical parameter editor during playback.</li> + <li>The Right Alt (or Alt Gr) key is not handled well by the keyboard configuration.</li> + <li>In Windows 98, the graphical parameter editor and instrument envelope editor grid display are messed up.</li> + <li>There is no really <em>convenient</em> way to find out what features of the tracker are supported by the original trackers (Impulse Tracker, Fasttracker 2, etc...) when working with those file formats...</li> + </ul> + + <h2>Contact</h2> + <p> + Helpful bug reports, new ideas and brave volunteers to test early development builds or contribute to the code are more than welcome!<br /> + Our issue tracker is located at <a href="http://bugs.openmpt.org/">http://bugs.openmpt.org/</a> and can be used to report bugs and feature requests.<br /> + You can also meet us at the ModPlug Central forums: <a href="http://forum.openmpt.org/">http://forum.openmpt.org/</a>. + </p> + + </body> +</html> \ No newline at end of file Property changes on: trunk/OpenMPT/packageTemplate/ReleaseNotesImages/1.20 ___________________________________________________________________ Added: tsvn:logminsize + 10 Added: trunk/OpenMPT/packageTemplate/ReleaseNotesImages/1.20/modified_files.png =================================================================== (Binary files differ) Property changes on: trunk/OpenMPT/packageTemplate/ReleaseNotesImages/1.20/modified_files.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/OpenMPT/packageTemplate/ReleaseNotesImages/general/modplug.png =================================================================== (Binary files differ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-05 16:25:49
|
Revision: 1263 http://modplug.svn.sourceforge.net/modplug/?rev=1263&view=rev Author: saga-games Date: 2012-05-05 14:43:55 +0000 (Sat, 05 May 2012) Log Message: ----------- [Mod] Updated various documents. [Fix] Settings: Trying to load the old "ramp" value from the INI file resulted in destroying the default ramp in/out settings on first run. [Mod] OpenMPT: Version is now 1.20.01.00 Modified Paths: -------------- trunk/OpenMPT/installer/filetypes.iss trunk/OpenMPT/installer/install-unmo3-free-itd.iss trunk/OpenMPT/installer/install-unmo3-free.iss trunk/OpenMPT/installer/install.iss trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/packageTemplate/History.txt trunk/OpenMPT/packageTemplate/OMPT_1.20_ReleaseNotes.html Modified: trunk/OpenMPT/installer/filetypes.iss =================================================================== --- trunk/OpenMPT/installer/filetypes.iss 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/installer/filetypes.iss 2012-05-05 14:43:55 UTC (rev 1263) @@ -29,6 +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\m15"; Description: "Ultimate Soundtracker (M15)"; Name: "associate_exotic\mdl"; Description: "DigiTrakker (MDL)"; Name: "associate_exotic\med"; Description: "OctaMED (MED)"; Name: "associate_exotic\mo3"; Description: "MO3 compressed modules (MO3)"; @@ -68,6 +69,7 @@ Root: HKCR; Subkey: ".gdm"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\gdm Root: HKCR; Subkey: ".imf"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\imf Root: HKCR; Subkey: ".j2b"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\j2b +Root: HKCR; Subkey: ".m15"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\m15 Root: HKCR; Subkey: ".mdl"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\mdl Root: HKCR; Subkey: ".med"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\med Root: HKCR; Subkey: ".mo3"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\mo3 Modified: trunk/OpenMPT/installer/install-unmo3-free-itd.iss =================================================================== --- trunk/OpenMPT/installer/install-unmo3-free-itd.iss 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/installer/install-unmo3-free-itd.iss 2012-05-05 14:43:55 UTC (rev 1263) @@ -21,7 +21,7 @@ begin if(IsTaskSelected('downloadmo3') And FileExists(ExpandConstant('{tmp}\openmpt-unmo3.dll.tmp'))) then begin - if(GetSHA1OfFile(ExpandConstant('{tmp}\openmpt-unmo3.dll.tmp')) <> '79de7b1476bbde064951c6946cf315a2') then + if(GetSHA1OfFile(ExpandConstant('{tmp}\openmpt-unmo3.dll.tmp')) <> 'd3dcfeed40204cfdc5fff505c8cd66d557d6ba7b') then begin MsgBox('Warning: unmo3.dll has been downloaded, but its checksum is wrong! This means that the downloaded file might corrupted or manipulated. The file has thus not been installed. Please obtain unmo3.dll from http://openmpt.org/ and verify its checksum.', mbCriticalError, MB_OK) end else Modified: trunk/OpenMPT/installer/install-unmo3-free.iss =================================================================== --- trunk/OpenMPT/installer/install-unmo3-free.iss 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/installer/install-unmo3-free.iss 2012-05-05 14:43:55 UTC (rev 1263) @@ -20,7 +20,7 @@ begin if(IsTaskSelected('downloadmo3') And FileExists(ExpandConstant('{tmp}\openmpt-unmo3.dll.tmp'))) then begin - if(GetSHA1OfFile(ExpandConstant('{tmp}\openmpt-unmo3.dll.tmp')) <> '79de7b1476bbde064951c6946cf315a2') then + if(GetSHA1OfFile(ExpandConstant('{tmp}\openmpt-unmo3.dll.tmp')) <> 'd3dcfeed40204cfdc5fff505c8cd66d557d6ba7b') then begin MsgBox('Warning: unmo3.dll has been downloaded, but its checksum is wrong! This means that the downloaded file might corrupted or manipulated. The file has thus not been installed. Please obtain unmo3.dll from http://openmpt.org/ and verify its checksum.', mbCriticalError, MB_OK) end else Modified: trunk/OpenMPT/installer/install.iss =================================================================== --- trunk/OpenMPT/installer/install.iss 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/installer/install.iss 2012-05-05 14:43:55 UTC (rev 1263) @@ -73,6 +73,7 @@ Source: packageTemplate\readme.txt; DestDir: {app}; Flags: ignoreversion Source: ..\packageTemplate\History.txt; DestDir: {app}; Flags: ignoreversion +Source: ..\packageTemplate\OpenMPT Manual.pdf; DestDir: {app}; Flags: ignoreversion ; release notes Source: ..\packageTemplate\ReleaseNotesImages\general\*.*; DestDir: {app}\ReleaseNotesImages\general\; Flags: ignoreversion sortfilesbyextension Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2012-05-05 14:43:55 UTC (rev 1263) @@ -348,7 +348,11 @@ gdWFIRCutoff = static_cast<double>(CMainFrame::GetPrivateProfileLong("Sound Settings", "ResamplerWFIRCutoff", Util::Round<long>(gdWFIRCutoff * 100.0), iniFile)) / 100.0; // Ramping... first try to read the old setting, then the new ones - glVolumeRampUpSamples = glVolumeRampDownSamples = CMainFrame::GetPrivateProfileLong("Sound Settings", "VolumeRampSamples", glVolumeRampUpSamples, iniFile); + const long volRamp = CMainFrame::GetPrivateProfileLong("Sound Settings", "VolumeRampSamples", -1, iniFile); + if(volRamp != -1) + { + glVolumeRampUpSamples = glVolumeRampDownSamples = volRamp; + } glVolumeRampUpSamples = CMainFrame::GetPrivateProfileLong("Sound Settings", "VolumeRampUpSamples", glVolumeRampUpSamples, iniFile); glVolumeRampDownSamples = CMainFrame::GetPrivateProfileLong("Sound Settings", "VolumeRampDownSamples", glVolumeRampDownSamples, iniFile); Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/mptrack/version.h 2012-05-05 14:43:55 UTC (rev 1263) @@ -18,8 +18,8 @@ //Version definitions. The only thing that needs to be changed when changing version number. #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 -#define VER_MINOR 00 -#define VER_MINORMINOR 87 +#define VER_MINOR 01 +#define VER_MINORMINOR 00 //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/History.txt =================================================================== --- trunk/OpenMPT/packageTemplate/History.txt 2012-05-05 11:00:19 UTC (rev 1262) +++ trunk/OpenMPT/packageTemplate/History.txt 2012-05-05 14:43:55 UTC (rev 1263) @@ -10,1143 +10,1467 @@ (tx XYZ): thanks to XYZ for telling us about the bug / requesting the feature +Developers: +<initials> nick name / real name [email @openmpt.org] + <al> Relabs / Ahti Leppänen [relabs] + <ec> Ericus / Eric Chavanon [ericus] + <js> Saga Musix / Johannes Schultz [sagamusix] + <rf> rewbs / Robin Fernandes [rewbs] + <sp> pelya / Sergiy Pylypenko [pelya] + <tn> plastik_s / Trevor Nunes [plastik_s] +Patch submitters: + <cm> kode54 / Chris Moeller + <ih> xaimus / Imran Hameed + <ks> coda / Ken Snyder + + +v1.20.01.00 (May 2012, revision 1263) +------------------------------------- +General tab + [Imp] <js> Like the plugin preset box, the plugin parameter selection box is now only populated when it is focussed, to avoid delays with plugins that have tons of parameters. + [Imp] <js> Default global volume display is now limited to 0...64 (instead of 0...128) for S3M (http://forum.openmpt.org/index.php?topic=4658.0). + [Mod] <js> Default global volume is not available anymore in the XM format, since it is not supported by the original format. + [Fix] <js> Switching between plugin presets didn't update the plugin parameter display. + [Fix] <js> When enabling surround for a channel, panning was not reset properly for playing tracks. + +Pattern tab + [New] <js> Added an option to select a whole channel when double-clicking a pattern cell (tx ko0x). + [New] <js> Added an option to display the default volume setting of a sample in the volume column if it is empty (obviously inspired by Impulse Tracker). + [New] <js> It is now possible to record incoming MIDI aftertouch messages to patterns using volume commands or MIDI Macros (http://bugs.openmpt.org/view.php?id=195). + [New] <js> New shortcuts: Increase / Decrease Row Spacing (http://bugs.openmpt.org/view.php?id=181). + [Imp] <js> Adding / removing channels through the pattern editor now creates an undo point instead of clearing the undo log completely. + [Imp] <js> Parameter Control Events have an edit memory now and adhere to the row spacing setting (tx cce, http://bugs.openmpt.org/view.php?id=190). + [Imp] <js> Added an order list context menu item to add a separator (+++) index. + [Imp] <js> When recording note offs in sample mode, Note Cuts are inserted instead of Note Offs. + [Imp] <js> Song position retrieval also works for sub tunes now, so song properties are restored properly when starting playback from a sub tune (http://forum.openmpt.org/index.php?topic=4578.0). + [Imp] <js> When trying to paste but no pattern data was found in the system clipboard, previously copied pattern data is now regained from an internal clipboard. + [Mod] <js> Renamed X Param to Parameter Extension. + [Mod] <js> Split keyboard settings now affect record groups: If there are channels assigned to both record groups, the lower part of the split keyboard is recorded into record group 2, the higher part is recorded into group 1 (http://forum.openmpt.org/index.php?topic=4568.0). + [Mod] <js> Shift-Selecting now uses the select key (which is Shift by default) instead of the hard-coded shift key. + [Mod] <js> Changed maximum width of pattern display to allow for wider displays than 4096 pixels (http://bugs.openmpt.org/view.php?id=215). + [Mod] <js> Changed maximum undo steps to 100,000. + [Fix] <js> When changing a note's octave, the triggered note was not stopped on key-up since the early OpenMPT 1.17 days (http://forum.openmpt.org/index.php?topic=4718.0). + [Fix] <js> Keyboard Split instrument setting was broken in OpenMPT 1.19. + [Fix] <js> Moving channels and then undoing the move doesn't screw up channel settings anymore (http://bugs.openmpt.org/view.php?id=156). + [Fix] <js> When undoing an edit switches to another pattern, OpenMPT tries to find a linked order for this pattern, so that continuous scroll keeps working (http://bugs.openmpt.org/view.php?id=189). Might not work reliably if the same pattern is used twice. + [Fix] <js> When duplicating a pattern sequence that starts with a non-existing pattern (e.g. +++), the pattern view didn't update properly so editing was still taking place in the previously selected pattern (confusing!) + [Fix] <js> Instruments are now faded out properly when editing XM modules. + [Fix] <js> Using Keyboard Split, it was possible to input unsupported notes (e.g. C-0 in MOD files). + [Fix] <js> It was possible to interpolate between a note and e.g. note cut, but it was not possible to interpolate between a note and no note. + [Fix] <js> Resizing a pattern didn't create an undo point. + [Fix] <js> Pattern names were not duplicated (http://bugs.openmpt.org/view.php?id=208). + [Fix] <js> Entering chords didn't do anything if only the note at the cursor position differed from previously entered pattern data. + [Fix] <js> The Reset Channel shortcut and the shortcut for setting Row Spacing to 9 never worked. + +Pattern tab::Note Properties + [Imp] <js> Better explanation of the MOD E5x effect parameter. + [Fix] <js> When showing the properties of a #xx (Parameter Extension) effect, negative values could have been shown. + [Fix] <js> Plugin indices for Parameter Control Events were off by one. + +Pattern tab::Find/Replace + [Imp] <js> Swapped channel numbers in the channel search feature are now treated correctly - if you enter e.g. 15 as the first channel and 3 as the second channel, channels 3 through 15 will be searched. + [Imp] <js> Volume column parameters are limited better now. It's still possible to do something like "Search for volume command d, replace by volume parameter 24", though... (don't do it!) + [Imp] <js> Follow Song isn't turned off anymore when using Find/Replace and the song isn't actually playing (http://bugs.openmpt.org/view.php?id=229). + [Imp] <js> Find/Replace also updates the order list with the correct order now - this doesn't work across multiple sequences yet, though (http://bugs.openmpt.org/view.php?id=152). + [Fix] <js> Replace instrument -1 didn't work as expected on instrument number 1. + [Fix] <js> Volume command parameters are now sanitized on replace (previously, it was possible to e.g. replace "v24" with "d", which would have generated the invalid command d24). + [Fix] <js> Replacing "no note" with note + 1 or note + 12 will not create C-0 / B-0 notes in the pattern anymore. + +Sample tab + [New] <js> Experimental feature: A Sample Tuner which tunes the sample to a specified note. + [Imp] <js> When changing XM autovibrato settings, they are now automatically propagated to other samples refererred by the same instrument. + [Mod] <js> Loops are now automatically enabled when setting loop points in the sample editor + [Mod] <js> Changed maximum undo steps to 100,000. + [Fix] <js> Pasting samples didn't copy over some sample settings (vibrato, etc.) if sample loops were enabled. + [Fix] <js> WAV Loading / Saving didn't consider RIFF padding bytes since... forever. Old broken samples (only 8-Bit Mono samples with an odd length are affected) should still load correctly. + [Fix] <js> Saving samples as WAV didn't save sample settings properly. + [Fix] <js> Deleting sample data adjusted loop points, but not sustain points. + [Fix] <js> Samples created using the "add silence / resize to" button didn't show up in the pattern editor's instrument list instantly. + [Fix] <js> Crossfade keyboard shortcut was broken. + [Fix] <js> Sometimes, the correct sample was not displayed after switching from another tab. + [Fix] <js> When converting between IT / MPTM and XM, the auto vibrato and sample pan limits were not updated instantly. + [Fix] <js> Saving and loading loop points in WAV samples is now done according to the RIFF standard (in OpenMPT, the loop end is exclusive, in the RIFF standard it is inclusive). Looped samples saved with older versions of OpenMPT are still imported correctly. + [Fix] <js> When loading multiple samples at once, existing samples are not overwritten anymore. + [Fix] <js> When cleaning up samples, the sample spin button is now updated instantly. + +Instrument tab + [Imp] <js> Better default values for loop points are chosen when enabling envelope (sustain) loops. + [Imp] <js> The sample mapping dialog accepts mouse dragging now. + [Imp] <js> Zxx value for the selected cutoff value is now shown next to the cutoff frequency (http://bugs.openmpt.org/view.php?id=36). + [Imp] <js> Filter settings and random variation sliders now have tooltips displaying the actual settings / swing variation. + [Imp] <js> When replacing an existing instrument, the replacement / deletion of the previously assigned samples can now be undone. + [Mod] <js> Two envelope points cannot share the same tick anymore in normal mode as well - since there is no interpolation happening between ticks anyway, this is no limitation at all. + [Mod] <js> Loading an instrument will not put samples into slots referenced by other instruments, even if those slots are empty (http://bugs.openmpt.org/view.php?id=213). + [Mod] <js> When assigning an instrument plugin, any sample associations are removed if they point to empty samples or if the user confirms the action. + [Mod] <js> Allow MIDI banks up to 16384 (only tested theoretically - do any plugins actually support that many banks?) + [Mod] <al> A newly added instrument is no longer assigned to an already existing but unreferenced sample. + [Fix] <js> Instruments are now faded out properly when editing an XM module. This means that sustain points can now also be tested properly. + [Fix] <js> Filter frequency display is now updated instantly when toggling the cutoff checkbox. + [Fix] <js> Loading instruments from other modules is no longer limited to 32 samples. + [Fix] <js> Fixed possible stack corruption when loading instruments into XM files. + +Treeview + [Imp] <js> The limit of 32 displayed song items has been removed. + [Imp] <js> If available, drum keys use key names provided by the soundfont instead of pre-defined drum key names. + [Imp] <js> All supported module files are now shown in the directory browser by default, even if "Show All Files" is disabled. + [Fix] <js> Fixed mnemonic shortcuts in some context menus. + +Mod Conversion + [Imp] <js> When converting XM to S3M / IT and there is pxx and Cxx in the same event, the commands are swapped (instead of simply deleting the Cxx command). + [Imp] <js> When converting to XM, samples are automatically converted to instruments if there are no instruments yet. + [Imp] <js> Instrument numbers next to Note-Offs are now removed when converting to XM. + [Imp] <js> Envelope loop behaviour is now fixed automatically when converting between XM and IT / MPTM. + [Imp] <js> Sample undo history is not lost anymore during conversion. + [Fix] <js> IT <-> XM auto vibrato and panning slide conversion were incorrect. + [Fix] <js> Instrument fadeout is now limited properly when converting from XM to IT / MPTM. + +MIDI Macros + [New/Fix] <js> The MIDI macro system has been rewritten completely and is now (hopefully) 99% compatible with IT's MIDI macros. Some macro letters have been changed / added, see the "macro help" button in the macro settings for more information (http://bugs.openmpt.org/view.php?id=94). + [Imp] <js> Added channel and polyphonic aftertouch to MIDI Macro presets. + [Fix] <js> MIDI Macros for controlling plugin parameters 128 through 131 were broken since probably forever (they did nothing). + +VST / DMO Plugins + [New] <js> OpenMPT ships with a MIDI Input / Output plugin now. It can be used to send incoming MIDI Events to other plugins or send MIDI events to external MIDI gear. + [New] <js> Plugins can now send MIDI events to chained plugins. Useful for e.g. LFO or arpeggiator plugins. + [New] <js> Added "mappped" MIDI channels (like in Impulse Tracker). If a plugin's MIDI Channel is set to "mapped" in the instrument editor, note data is transmitted on a triggered note's pattern channel modulo 16. + [New] <js> Experimental built-in support for JBridge. If you run OpenMPT with admin privileges now, you can directly run 64-Bit VST plugins in OpenMPT. + [Imp] <js> Rewrote default plugin editor (the one that is used for plugins with no custom GUI). Multiple parameters are shown at the same time, with the same automation functionality as custom editors (record to pattern, automatic MIDI Mapping by pressing Shift, etc...), remembers window position, etc... (http://forum.openmpt.org/index.php?topic=1974.0) + [Imp] <js> Searching for multiple unknown plugins will now open only one browser window. + [Imp] <js> Named DMO parameter values are now displayed properly. + [Imp] <js> Preset browser in plugin window has been improved for plugins with many presets (like Synth1). + [Imp] <js> OpenMPT also checks for the new VST DLL entry point ("VSTPluginMain") when loading plugins now, so plugins that only export "VSTPluginMain" and not "main" will now also load (if there are any). + [Imp] <js> If a plugin fails to load and crashes OpenMPT, it is not loaded the next time OpenMPT is started anymore, to prevent infinite crash loops. + [Imp] <js> Added support for plugins that change the number of inputs / outputs during runtime. + [Imp] <js> Preset menu structure in the plugin window is now updated when the plugin tells to do so. + [Imp] <js> Added support for the (deprecated) GetPreviousPlug / GetNextPlug VST opcodes. + [Mod] <js> MIDI portamento on muted channels is not processed anymore (http://bugs.openmpt.org/view.php?id=219). + [Mod] <js> Warnings for known troublesome plugins are now shown when adding plugins to the plugin library instead of when adding them to a song. + [Mod] <js> MIDI Program and Bank indices start at 1 in all places now. + [Mod] <js> Parameter indices are always displayed in decimal instead of hex and in a more consistent manner throughout the whole interface. + [Mod] <js> Knob mode is set to linear (instead of circular) mouse actions for VST plugins that support it. + [Mod] <js> When using Randomise Parameters, only automatable parameters are now randomised. + [Mod] <js> If a plugin DLL is not found, OpenMPT tries to find it in the plugin directory instead of the settings directory. + [Fix] <js> Custom plugin editors don't have a grey bar of nothingness at the bottom anymore in semi-random cases. + [Fix] <js> Fixed potential problems with multi-threading VSTs when loading a plugin for the first time (tx manx). + +VST::Specific Plugin Fixes + [Fix] <js> When automating parameters from a plugin GUI, it is first checked whether the parameter can actually be automated. This fixes usage of the Shift key (open MIDI Mapping dialog) in e.g. Ugo's Motion and at the same time makes the Shift key work again in Synth1. + [Fix] <js> Plugins with more than 32 output channels (e.g. Kontakt) do not crash anymore. + [Fix] <js> SynthEdit plugin settings are now always restored correctly when opening a saved module (http://bugs.openmpt.org/view.php?id=210). + [Fix] <js> TAL-NoiseMaker and other plugins based on JUCE do not crash anymore when jumping between orders while playback is disabled (tx herodotas). + +Playback + [Mod] <ih, js> Volume ramp up and ramp down are now two different settings. Ramp up is applied when increasing the volume and starting a sample, ramp down is applied when decreasing the volume or cutting the sample. The old behaviour can be achieved by using the same value for both settings. + [Mod] <js> The default ramp up setting is 16 samples (instead of 42 as before). + [Mod] <js> Global volume is now applied before all internal DSPs (http://bugs.openmpt.org/view.php?id=72). + [Mod] <js> Changed 4-Bit panning computation a bit, so that e.g. S80 is true left and S8F is true right. + [Mod] <js> Resonant filter mixing is now done with floating-point precision. This allows for greater compatibility with Impulse Tracker's resonant filter and eliminates unwanted extreme noises that previously appeared with certain samples, as well as broken filter coefficients at high playback samples rates. + [Fix] <js> When finishing a sustain loop that is behind a normal sample loop, sample playback is not simply stopped anymore. + [Fix] <js> Multiple fine pattern delays on the same row are now added up. + [Fix] <js> The length of a row is now (1 + Row Delay) * (Speed + Tick Delay) instead of ((1 + Row Delay) * Speed) + Tick Delay. + [Fix] <js> XM / MOD volume and panning slide nibble priority was wrong for slides with both nibbles set. This was only relevent for newly entered note slides, since slide commands loaded from files were automatically fixed (http://bugs.openmpt.org/view.php?id=242). + [Reg] <js> MMX-accelerated sample mixing has been disabled as it did not work properly with the floating-point precision filter mixing. + +IT + [Mod] <js> Newly created IT files have compatible playback mode enabled by default. + [Mod] <js> Saving: Files with filter envelopes use a different file version (IT 2.16 instead of IT 2.17) now. + [Fix] <js> Fixed volume and pan drifting when using Volume Swing / Pan Swing in compatible mode (tx Teasy). + [Fix] <js> Volume Swing range was 0 to 64 while it should be a percentage from 0 to 100 (old files are fixed automatically). + [Fix] <js> Multiple fine pattern delays on the same row weren't added up. + [Fix] <js> Channel and global volume slides with both nibbles set are now ignored. + [Fix] <js> Tone Portamento is now ignored if no note was previously playing. + [Fix] <js> If there are multiple row delay commands on the same row, only the leftmost command is considered. + [Fix] <js> Delayed notes that are on the same row as a row delay effect are be retriggered. + [Reg] <js> Removed restart position and Pitch/Tempo Lock from IT extensions. They can still be edited when loading an old IT file with restart position set or Pitch/Tempo Lock enabled, but for all other files, they are not available. + +IT::Compatible Playback Mode + [Fix] <js> New filter mode which pretty much sounds like Impulse Tracker's resonant filter (http://bugs.openmpt.org/view.php?id=8). The new filter mode is used iff "More IT compatible playback" is turned on and extended filter range is turned off. + [Fix] <js> The filter is turned on iff either the cutoff is not at maximum or the resonance is not at minimum. + [Fix] <js> No pan swing, panbrello, panning envelopes, etc. is applied on surround channels in compatible mode anymore (unless Quad Surround mode is enabled). + [Fix] <js> Sample and instrument panning overrides surround if Quad Surround is disabled (Test case: SmpInsPanSurround.it) + [Fix] <js> NNA settings are only recalled when a note entry is found. + [Fix] <js> A high offset effect next to a note erroneously applied the offset instantly. + [Fix] <js> Fixed behaviour when picking up notes after a SCx effect. + [Fix] <js> Envelopes are now paused correctly when using S77 / S79 / S7B. + [Fix] <js> If a sample stops before it would be retriggered using Qxy, it is not retriggered at all. + [Fix] <js> Envelope carry cannot pick up an instrument after a SCx note cut anymore. + [Fix] <js> Envelope loop vs. sustain loop checking priorities were wrong (http://schismtracker.org/scdev/res/1513.html). + +IT::Loading + [Imp] <js> Songs with no order items are now also accepted. + [Imp] <js> Songs made with MPT 1.0 alpha and beta versions are now shown as such in the version information. + [Imp] <js> Most files saved with OpenMPT's early "compatiblity export" are not detected as MPT 1.16 files anymore. + [Mod] <js> Some compatibility settings are now always applied (not only in IT compatible mode) and files saved with older versions of OpenMPT are "fixed" automatically to still work with the new settings. Affected settings are: Out-of-range global volume handling, SC0 / SD0 handling, Autovibrato with Sweep = 0, Pitch / Pan Separation depth, slide commands with both nibbles set, pitch envelope loops, Row Delay behaviour. + [Fix] <js> Envelope points are now sanitized better and envelope points with the high byte missing are now loaded correctly. + [Fix] <js> Instruments in IT files with no samples are now loaded correctly. + +MPTM + [Mod] <js> Some compatibility settings are now always applied (not only in IT compatible mode) and files saved with older versions of OpenMPT are "fixed" automatically to still work with the new settings. Affected settings are: Out-of-range global volume handling, SC0 / SD0 handling, Autovibrato with Sweep = 0, Pitch / Pan Separation depth, slide commands with both nibbles set, pitch envelope loops, Row Delay behaviour. + [Mod] <js> Changed default amplification settings from 64 / 128 / 128 to 128 / 48 / 48 as they were messing horribly with precision and could easily lead to distortion. + +XM + [Mod] <js> Newly created XM files have compatible playback mode enabled by default. + [Mod] <js> Some compatibility settings are now always applied (not only in XM compatible mode) and files saved with older versions of OpenMPT are "fixed" automatically to still work with the new settings. Affected settings are: Out-of-range global volume handling, portamento vs. offset priority. + [Fix] <js> Vibrato "ramp down" waveform is now played correctly (was previously played as "ramp up"). + [Fix] <js> Panning slide nibble priority (when both nibbles of the slide parameter are set) was wrong for XM files. + [Fix] <js> The first tick on a row was always "on" for XM tremor. + [Fix] <js> Creating a new XM file did not set the panning flag for the first (and only) sample. + +XM::Compatible Playback Mode + [Fix] <js> An instrument number (no matter what number) next to a note-off event recalls the default settings of the previously playing instrument. + [Fix] <js> Tone Portamento is ignored if it's combined with a note delay. + [Fix] <js> A great number of other mind-boggling combinations of Note Off, Instrument Number, Note Delay, etc... should also play more like in Fasttracker 2 now. + [Fix] <js> Great improvements with regards to E6x pattern loop handling in combination with pattern break / position jump effects. + [Fix] <js> Volume column tone portamento still had an effect memory. + [Fix] <js> An instrument number does not reset the bidi loop direction anymore. + [Fix] <js> The portamento target is not reset anymore when there is a note or instrument number with no portamento effect next to it. + [Fix] <js> Fixed handling of out-of-range notes (http://bugs.openmpt.org/view.php?id=217). + [Fix] <js> Length Calculation: E60 bug was not handled correctly if the last E6x command was on the last row of the pattern. + [Fix] <js> Envelope loop / sustain point priorities have been corrected. + [Fix] <js> Semi-fixed global volume commands: They are not applied on the first tick of a row anymore (unless pattern speed is 1). + +XM::Loading and Saving + [Imp] <js> Volume Column panning is now scaled better when loading or saving XM files, so it is translated to a 0...64 range instead of 2...62. + [Imp] <js> Saving: Samples that are not associated to any instrument are now tried to be written to XM files anyway (http://bugs.openmpt.org/view.php?id=234). + [Fix] <js> Saving: When saving an XM with no instruments, garbage instrument settings were written. + +S3M + [Fix] <js> Some commands (Dxy, Exx, Fxx, Ixy, Jxy, Kxy, Lxy, Qxy, Rxy, Sxy) use the last non-zero effect parameter as memory. This fixes for example Satellite One by Purple Motion. + [Fix] <js> Pattern loops have no per-channel memory in ST3 (tx Greasemonkey). + [Fix] <js> Amiga limits are now enfored correctly if the "preserve amiga limits" flag is set. + [Fix] <js> If there are multiple row delay commands on the same row, only the leftmost command is considered. + [Fix] <js> Delayed notes that are on the same row as a row delay effect are be retriggered. + [Reg] <js> \xx command has been removed from S3M format (existing tracks are updated automatically to use the Zxx command instead). + +S3M::Loading + [Imp] <js> Default channel panning is now scalled better when loading and saving, for a full 0...256 range. + [Imp] <js> PixPlay panning heuristics only apply to modules made with versions of ScreamTracker older than 3.20. + [Fix] <js> MIDI Macros are now cleared when loading S3M files saved with Impulse Tracker 2.13 or older (fixes BABYLON.S3M by Necros) + [Fix] <js> Some malicious S3M files could previously crash OpenMPT. + +MOD + [Fix] <js> Amiga limits are now enfored correctly in ProTracker 1.x mode. + [Imp] <js> Rewrote MOD magic parsing code a bit; can handle anything from 1 to 99 channel MODs now. + [Mod] <js> Removed MOD compatibility export, it is now always applied (but only oneshot samples are modified, and they are not modified in memory anymore). + +Other formats + [Imp] <js> Added hack-ish support for 32-bit float data to the WAV loader (the one that loads WAVs as modules, not as samples). + [Imp] <js> If opening a WAV file for rendering fails, the user can choose to retry opening the file. + [Imp] <js> UMX Loader: Instead of "scanning" Unreal files for modules, they are actually parsed correctly now. As a nice side effect, it is now also possible to load UAX files (collections of samples) from older Unreal Engine games as modules. + [Fix] <js> MIDI Import / Export: Exporting is no longer limited to the first 64 channels. MIDI files with any number of tracks can now be imported (previous limit was 64 tracks). + [Fix] <js> DBM Loader: Global volume command was broken since OpenMPT 1.19.02.00. + [Fix] <js> PSM16 Loader: Sample finetune and transpose should be correct now. + [Fix] <js> PTM Loader: Fixed sample names. + +Module cleanup + [Mod] <js> Reset Song Variables also cleans the MIDI Macros now. + [Fix] <js> Instrument to Sample conversion broke Parameter Control Events and note cuts / fades / offs. + [Fix] <js> Sustain loops behind sample loops are not ignored anymore when optimizing samples. + +Misc + [New] <al> Template modules can now be loaded and saved through the "File" menu. + [New] <al> Example modules can now be loaded from the "Help" menu. + [New] <ks> Keyboard shortcuts can now be assigned to incoming MIDI CCs. For now, this only works if the pattern, sample or instrument editor is focussed. + [New] <js> Instead of multiple modal message boxes, a single dialog with a list of unsaved files is now shown when closing the main window. If you don't like the new behaviour, use "Disable modern close dialog" in the general settings. + [New] <js> The default module type can now be set in mptrack.ini by setting DefaultModType in the [Misc] section, e.g. "DefaultModType=mptm" (tx herodotas, http://forum.openmpt.org/index.php?topic=4411.0). + [New] <js> Recent file list length can now be set through a hidden INI option, MRUListLength in [Misc] (up to 15 entries). + [New] <js> If a crash is encountered, OpenMPT tries to close the audio device (if it is still in use) and rescue all modified files. A memory dump is also created and can be used for debugging. + [New] <js> Added "Close All" shortcut + menu item (tx Wayfinder). + [New] <js> Added Finnish FT2 style keymap by cce. + [Imp] <js> Shortcuts are not processed anymore when a message box is shown. + [Imp] <js> Keyboard Config Dialog: Added a button to restore default configuration and a text field for searching keyboard shortcuts by name. + [Imp] <js> Added "/Portable" command line switch, which saves all settings in OpenMPT's directory (just like "UseAppDataDirectory=0" in the [Paths] section of mptrack.ini). + [Imp] <js> Compatibility export menu item is now greyed out for S3M and MPTM modules. + [Imp] <js> Plugin Manager: Buttons have mnemonics now, keyboard handler is disabled while the dialog is open, and the plugin list does not collapse anymore when removing a plugin (http://bugs.openmpt.org/view.php?id=186). + [Imp] <js> Added "Show Settings Folder" menu item to help menu. + [Imp] <js> Keyboard Settings: Added a search box, so finding a shortcut by name should be much easier now. + [Imp] <js> The "Amplify MIDI Velocity" option has been changed to use a freely adjustable amplification factor (instead of fixed x2 amplification). + [Mod] <js> Removed horribly esoteric sample "fixing" for MOD / S3M files that was applied when loading MOD / S3M files or modifying samples in them - it could very well break some totally fine samples. + [Mod] <js> Channel Manager: Playback is not stopped anymore when stopping when reordering / removing channels. + [Mod] <js> Song Properties: Modern and Alternative tempo mode is not shown for XM / IT files anymore by default, and deprecated playback flags are now greyed out unless used by the current module. Song flags are not updated "live" anymore. + [Mod] <js> Revamped MIDI Mapping and Tuning dialogs a bit. + [Mod] <js> Added some missing shortcuts to the default key bindings (tx Wayfinder). + [Mod] <js> Compatibility export hints are now hideable. + [Mod] <js> Updated libraries: unmo3.dll (2.4.0.3), SoundTouch (1.6.0), zlib (1.2.7). + [Fix] <js> Wave Export: Fixed infinitely looping export (http://forum.openmpt.org/index.php?topic=3874.0). + [Fix] <js> BPM approximation even works reliably when a module is not playing now. + [Fix] <js> Song length approximation for alternative tempo mode was compltely wrong (tx Bavi H). + [Fix] <js> Combo boxes will not disappear randomly that often anymore. + [Fix] <js> Comments tab: C-5 frequency is now displayed correctly in all formats. + [Fix] <js> MP3 Export shortcut was broken (http://bugs.openmpt.org/view.php?id=201). + [Reg] <js> Saving to another module format requires explicit module conversion now, as it was causing more trouble than doing good. Previously, it was possible to simply enter a different file extension in the "Save As" dialog, so editing an IT file and saving it as "foo.mod" would have saved it as a ProTracker MOD instead of an IT file with .mod extension. + + +v1.19.04.00 (September 2011, revision 1027) +------------------------------------------- +Pattern tab + [Imp] <js> MIDI controller changes that are not covered by MIDI Mapping also create an undo point now. + [Fix] <js> Parameter Control Event automation via MIDI Mapping didn't create an undo point if the cursor was in the first row or column (and if it wasn't, it stored too much undo data). + +Instrument tab + [Fix] <js> When editing the first envelope node while compatible playback mode was enabled, the node was moved to the second tick. + [Fix] <js> Aftertouch messages forwarded to plugins don't mark the module as modified anymore. + +Mod Conversion + [Fix] <js> Sample panning is now properly reset / disabled for MOD / S3M / XM files. + [Fix] <js> Various instrument properties were not cleared when converting from IT / MPTM to XM. + [Fix] <js> Sample sustain loops were also not removed when converting from IT / MPTM to XM. + +VST / DMO Plugins + [Fix] <al> VST host version fields didn't follow the actual version of OpenMPT. + +VST::Specific Plugin Fixes + [Fix] <js> Plugins based on the JUCE framework (e.g. TAL-NoiseMaker) don't crash anymore during WAV export. + [Fix] <ih> Some multi-input plugins like Guitar Rig will not crash anymore. + +Other formats + [Fix] <js> Fixed vulnerabilities in WAV, AMS and DSM loaders (http://secunia.com/advisories/45131/). + +Misc + [Fix] <js> Network paths starting with "\\" are now loaded properly from settings. Previously, they were treated as relative paths. + [Fix] <js> Adding plugins through the main menu didn't mark the module as modified (http://bugs.openmpt.org/view.php?id=163). + + v1.19.03.00 (July 2011, revision 921) ------------------------------------- General tab - [Imp] <Jojo> When editing panning, surround is disabled and when enabling surround, panning is reset. - [Imp] <Jojo> When moving a plugin to another slot, plugins routing their output to the selected plugin are now taken into account when choosing a default slot to move the plugin to. + [Imp] <js> When editing panning, surround is disabled and when enabling surround, panning is reset. + [Imp] <js> When moving a plugin to another slot, plugins routing their output to the selected plugin are now taken into account when choosing a default slot to move the plugin to. Pattern tab - [Imp] <Jojo> Channel Surround status is now also indicated in the status bar. - [Fix] <Jojo> When playing a pattern that is actually not in the sequence and that has more rows than the last played order item, a crash could occour while playing those extra rows. (Welcome to episode 2938 of "this should not have happened afterall") - [Fix] <Jojo> Shift + Channel Dragging killed the last channel (http://bugs.openmpt.org/view.php?id=133). - [Fix] <Jojo> When using the pattern play controls (f.e. "Replay Pattern") on a pattern that isn't played in the normal play sequence, tempo and global volume commands on the first played row are not ignored anymore. - [Fix] <Jojo> Songs shouldn't stop anymore after playing them one time and if playback was initially started using a pattern play mode with loop enabled (http://bugs.openmpt.org/view.php?id=11) - [Fix] <Jojo> When overwriting PC notes with normal notes, the pattern cell is now cleared properly. - [Fix] <Jojo> Using the "Paste Pattern" menu entry in the order list didn't refresh the pattern display. + [Imp] <js> Channel Surround status is now also indicated in the status bar. + [Fix] <js> When playing a pattern that is actually not in the sequence and that has more rows than the last played order item, a crash could occour while playing those extra rows. (Welcome to episode 2938 of "this should not have happened afterall".) + [Fix] <js> Shift + Channel Dragging killed the last channel (http://bugs.openmpt.org/view.php?id=133). + [Fix] <js> When using the pattern play controls (e.g. "Replay Pattern") on a pattern that isn't played in the normal play sequence, tempo and global volume commands on the first played row are not ignored anymore. + [Fix] <js> Songs shouldn't stop anymore after playing them one time and if playback was initially started using a pattern play mode with loop enabled (http://bugs.openmpt.org/view.php?id=11) + [Fix] <js> When overwriting Parameter Control Events with normal notes, the pattern cell is now cleared properly. + [Fix] <js> Using the "Paste Pattern" menu entry in the order list didn't refresh the pattern display. Sample tab - [Imp] <Jojo> When selecting parts of the sample, the selection range is now also displayed in samples, not only seconds (tx jmkz, http://bugs.openmpt.org/view.php?id=136). - [Imp] <Jojo> When changing the sample's global volume while removing DC offset, the change is now instantly applied to all channels that are currently playing the sample. - [Fix] <Jojo> 8-Bit Stereo samples were not saved correctly (tx jmkz, http://bugs.openmpt.org/view.php?id=153). + [Imp] <js> When selecting parts of the sample, the selection range is now also displayed in samples, not only seconds (tx jmkz, http://bugs.openmpt.org/view.php?id=136). + [Imp] <js> When changing the sample's global volume while removing DC offset, the change is now instantly applied to all channels that are currently playing the sample. + [Fix] <js> 8-Bit Stereo samples were not saved correctly (tx jmkz, http://bugs.openmpt.org/view.php?id=153). Instrument tab - [Imp] <Jojo> When in compatible mode, two envelope points cannot share the same tick anymore. - [Fix] <Jojo> Suggested filename when saving instrument was sometimes cut off. + [Imp] <js> Two envelope points cannot share the same tick anymore in compatible mode. + [Fix] <js> Suggested filename when saving instrument was sometimes cut off. -VST - [Fix] <Jojo> When a plugin requests song position in nano seconds, the correct value should now be returned. - [Fix] <Jojo> Loading a VST preset (fxp) didn't mark the document as modified (tx BooT-SectoR-ViruZ) +VST / DMO Plugins + [Fix] <js> When a plugin requests song position in nano seconds, the correct value is now returned (tx coda). + [Fix] <js> Loading a VST preset (fxp) didn't mark the document as modified (tx BooT-SectoR-ViruZ) Playback - [Fix] <Jojo> Filters in XM files aren't reset with every new note anymore (this broke some versions ago). + [Fix] <js> Filters in XM files aren't reset with every new note anymore (this broke some versions ago). IT - [Fix] <Jojo> Saving IT instruments (in both IT and ITI files) with an invalid sample map crashed the tracker (http://bugs.openmpt.org/view.php?id=142) - [Fix] <Jojo> (Also applies to MOD) When swapping samples on the fly and the current playback position is beyond the new sample's length, it's reset to 0. + [Fix] <js> Saving IT instruments (in both IT and ITI files) with an invalid sample map crashed the tracker (http://bugs.openmpt.org/view.php?id=142) + [Fix] <js> (Also applies to MOD) When swapping samples on the fly and the current playback position is beyond the new sample's length, it's reset to 0. MPTM - [Fix] <Jojo> Saving long envelopes (> 25 envelope points) in the MPTM format was broken since... well, actually, it never worked in any officially released version. Now you can finally have up to 240 envelope points. + [Fix] <js> Saving long envelopes (> 25 envelope points) in the MPTM format was broken since... well, actually, it never worked in any officially released version. Now you can finally have up to 240 envelope points. Other formats - [Fix] <Jojo> ITP Saver: Fixed nasty bug when the internal order length was not 256. - [Fix] <Jojo> IMF Loader: Orpheus' 8-Bit cutoff range was not converted to MPT's 7-Bit range. + [Fix] <js> ITP Saver: Fixed nasty bug when the internal order length was not 256. + [Fix] <js> IMF Loader: Orpheus' 8-Bit cutoff range was not converted to MPT's 7-Bit range. Misc - [Imp] <Jojo> Tagging: ID3 tags contain a TDRC tag instead of TYER now, as recommend by the ID3v2.4 standard. Also added a TPBM (beats per minute) tag. - [Imp] <Jojo> Hack detection also notifies about stereo samples in XM files now. - [Imp] <Jojo> Fixed tab order in the pitch shift dialog. - [Mod] <Jojo> Song Properties: Legacy Mixmodes RC1 and RC2 are now only displayed if they are actually used by the module. - [Mod] <Jojo> When loading a module made with a newer version of OpenMPT which only differs in the build number (last number in the version), no warning is shown anymore. For all other cases, the warning is now also shown for MPTM files. - [Mod] <Jojo> If opening MIDI In fails, the MIDI config dialog is shown. - [Fix] <Jojo> MP3 export should no longer result in a heap corruption and thus crash the tracker (http://bugs.openmpt.org/view.php?id=97). - [Fix] <Jojo> Rendering sub songs to WAV resulted in an endless render loop. - [Fix] <Jojo> Setup Dialog: Fixed the checkbox list so that it doesn't look weird under Wine and doesn't crash when compiling OpenMPT with VS2010 (tx jmkz). + [Imp] <js> Tagging: ID3 tags contain a TDRC tag instead of TYER now, as recommend by the ID3v2.4 standard. Also added a TPBM (beats per minute) tag. + [Imp] <js> Hack detection also notifies about stereo samples in XM files now. + [Imp] <js> Fixed tab order in the pitch shift dialog. + [Mod] <js> Song Properties: Legacy Mixmodes RC1 and RC2 are now only displayed if they are actually used by the module. + [Mod] <js> When loading a module made with a newer version of OpenMPT which only differs in the build number (last number in the version), no warning is shown anymore. For all other cases, the warning is now also shown for MPTM files. + [Mod] <js> If opening MIDI In fails, the MIDI config dialog is shown. + [Fix] <js> MP3 export will no longer result in a heap corruption and thus crash the tracker (http://bugs.openmpt.org/view.php?id=97). + [Fix] <js> Rendering sub songs to WAV resulted in an endless render loop. + [Fix] <js> Setup Dialog: Fixed the checkbox list so that it doesn't look weird under Wine and doesn't crash when compiling OpenMPT with VS2010 (tx jmkz). v1.19.02.00 (May 2011, revision 871) ------------------------------------ Pattern tab - [New] <Jojo> Channels can now be moved by dragging their channel header. Holding Shift while doing so duplicates the channel. - [Imp] <Jojo> Moving channels through the channel manager creates an undo point now. - [Fix] <Jojo> Order list info text now truncates list length after the first "---" pattern for MOD files in hex display mode as well. + [New] <js> Channels can now be moved by dragging their channel header. Holding Shift while doing so duplicates the channel. + [Imp] <js> Moving channels through the channel manager creates an undo point now. + [Fix] <js> Order list info text now truncates list length after the first "---" pattern for MOD files in hex display mode as well. Pattern tab::Note properties - [Fix] <Jojo> Axx is not limited to value 7F anymore in IT / S3M format. + [Fix] <js> Axx is not limited to value 7F anymore in IT / S3M format. -VST - [New] <Jojo> New menu entry in the plugin editor: Create instrument from plugin - [Fix] <Jojo> Fixed note handling in VST editor of plugins that actually don't support MIDI input (http://bugs.openmpt.org/view.php?id=102) +VST / DMO Plugins + [New] <js> New menu entry in the plugin editor: Create instrument from plugin. + [Fix] <js> Fixed note handling in plugin editor for VSTs that actually don't support MIDI input (http://bugs.openmpt.org/view.php?id=102) Mod Conversion - [Imp] <Jojo> Improved conversion of Sxx (IT / S3M) and PC Notes. - [Mod] <Jojo> When converting from MOD / S3M to XM / IT, compatible play is automatically enabled. - [Fix] <Jojo> Sustain loop conversion didn't work + [Imp] <js> Improved conversion of Sxx (IT / S3M) and Parameter Control Events. + [Mod] <js> When converting from MOD / S3M to XM / IT, compatible play is automatically enabled. + [Fix] <js> Sustain loop conversion didn't work. Playback - [Fix] <Jojo> The first triggered note in the pattern / sample / instrument editor is not cut off anymore (tx C-jeff, http://bugs.openmpt.org/view.php?id=123) + [Fix] <js> The first triggered note in the pattern / sample / instrument editor is not cut off anymore (tx C-jeff, http://bugs.openmpt.org/view.php?id=123) IT - [Imp] <Jojo> When clearing MIDI macros during loading, only the Zxx macros are cleared, but not the global (currently unused) configuration. - [Fix] <Jojo> Panning slides with both parameter nibbles set were not ignored in compatible mode. + [Imp] <js> When clearing MIDI macros during loading, only the Zxx macros are cleared, but not the global (currently unused) configuration. +IT::Compatible Playback Mode + [Fix] <js> Panning slides with both parameter nibbles set were not ignored in compatible mode. + XM - [Fix] <Jojo> When using compatibility export, the number of samples per instrument is now limited to 16. + [Fix] <js> When using compatibility export, the number of samples per instrument is now limited to 16. MOD - [Imp] <Jojo> Instead of cutting the order list after the first --- pattern, such order items are simply removed from the saved order list. (http://bugs.openmpt.org/view.php?id=118) - [Fix] <Jojo> "+++" separator patterns were allowed in MOD files, which made them break in other trackers / players. (http://bugs.openmpt.org/view.php?id=118) + [Imp] <js> Instead of cutting the order list after the first --- pattern, such order items are simply removed from the saved order list. (http://bugs.openmpt.org/view.php?id=118) + [Fix] <js> "+++" separator patterns were allowed in MOD files, which made them break in other trackers / players (http://bugs.openmpt.org/view.php?id=118). S3M - [Imp] <Jojo> When clearing MIDI macros during loading, only the Zxx macros are cleared, but not the global (currently unused) configuration. + [Imp] <js> When clearing MIDI macros during loading, only the Zxx macros are cleared, but not the global (currently unused) configuration. Other formats - [Imp] <Jojo> DMF Loader was rewritten completely and is a whole lot more accurate now. - [Fix] <Jojo> J2B Loader: Empty sample slots are now treated correct in new (RIFF AM) J2B files. - [Fix] <Jojo> DBM Loader: Global volume was scaled wrong. - [Fix] <Jojo> 8SVX Loader: If no sample could be found in the file, the loader does not claim to have successfully loaded a sample anymore. (http://bugs.openmpt.org/view.php?id=117) + [Imp] <js> DMF Loader was rewritten completely and is a whole lot more accurate now. + [Fix] <js> J2B Loader: Empty sample slots are now treated correctly in new (RIFF AM) J2B files. + [Fix] <js> DBM Loader: Global volume was scaled wrong. + [Fix] <js> 8SVX Loader: If no sample could be found in the file, the loader does not claim to have successfully loaded a sample anymore (http://bugs.openmpt.org/view.php?id=117). Misc - [New] <Jojo> OpenMPT can now automatically check for updates (daily / weekly / monthly) - [Mod] <Jojo> "Embed MIDI macros" is now only enabled during song creation if the user's default MIDI macro setup differs from standard configuration. - [Fix] <Jojo> When using "Convert instruments to samples" in the Song Cleanup dialog, "Remove samples associated with an instrument" actually destroyed all samples. - [Reg] <Jojo> Removed hidden INI flag to suppress warnings when encountering keymaps with unknown items. This option was introduced when faulty keymaps threw multiple message boxes, but now it's just one and it shouldn't be ignored... + [New] <js> OpenMPT can now automatically check for updates (daily / weekly / monthly). + [Mod] <js> "Embed MIDI macros" is now only enabled during song creation if the user's default MIDI macro setup differs from standard configuration. + [Fix] <js> When using "Convert instruments to samples" in the Song Cleanup dialog, "Remove samples associated with an instrument" actually destroyed all samples. + [Reg] <js> Removed hidden INI flag to suppress warnings when encountering keymaps with unknown items. This option was introduced when faulty keymaps threw multiple message boxes, but now it's just one and it shouldn't be ignored... v1.19.01.00 (April 2011, revision 836) -------------------------------------- Pattern tab - [New] <Jojo> Clicking and dragging the row numbers selects the whole row in Excel / Calc style (http://bugs.openmpt.org/view.php?id=45) - [New] <Jojo> The new keyboard shortcuts "Select beat" and "Select measure" can be used to automatically extend the current selection to the beat / measure boundaries. - [New] <Jojo> Experimental feature: Play the whole pattern row when entering notes and chords into the pattern editor. This can be enabled from the setup screen. - [Mod] <Jojo> Using the Goto Dialog updates channel parameters and sets the elapsed time now. (http://bugs.openmpt.org/view.php?id=28) - [Mod] <Jojo> Undo steps have been increased from 100 to 1000. - [Fix] <Jojo> Shrink selection is more consistent with Shrink pattern now: Entries on odd rows are not ignored anymore if there is no entry in the even rows. Also, cleaning of the pattern after shrinking the selection has been fixed - it cleaned whole commands instead of just the selected parts of a command. (http://bugs.openmpt.org/view.php?id=89) - [Fix] <Jojo> Cursor paste was possible even when editing was disabled. - [Fix] <Jojo> Using Right-Click -> Change Plugin on PC notes did not work for plugin numbers that were higher than the highest instrument number. - [Fix] <Jojo> When entering chords into the pattern editor, the module was only marked as modified if the base note of the chord was changed. - [Fix] <Jojo> When jumping to an order which is normally not played, the song variables are now reset (previously, if the main song had f.e. a global volume fade out at the end, this was retained when switching to an unplayed order, effectively muting all sub songs). - [Fix] <Jojo> OpenMPT does not crash anymore when applying the Amplify command on a pattern selection that just covers the note / instrument column of the first channel. - [Fix] <Jojo> Queueing a "---" or "+++" item now automatically moves the queue "cursor" to the next available pattern. Previously, queueing a "---" pattern restarted the song. - [Fix] <Jojo> Changing a channel name from the pattern editor didn't mark the document as modified (http://bugs.openmpt.org/view.php?id=65) - [Fix] <Jojo> When restarting a pattern, the song timer was not reset properly. - [Fix] <Jojo> Entering a note-off event in the MOD format created an unnecessary undo event. - [Fix] <Jojo> Automation data is not written to the pattern if the current module format does not support smooth midi macros. - [Fix] <Jojo> Selections were not clamped properly to the end of the pattern sometimes. - [Reg] <Jojo> The "Position aware timer" option is gone. The position aware timer is now automatically used. It was optional in the first place because of some buggy code, which is now fixed. + [New] <js> Clicking and dragging the row numbers selects the whole row in Excel / Calc style (http://bugs.openmpt.org/view.php?id=45) + [New] <js> The new keyboard shortcuts "Select beat" and "Select measure" can be used to automatically extend the current selection to the beat / measure boundaries. + [New] <js> Experimental feature: Play the whole pattern row when entering notes and chords into the pattern editor. This can be enabled from the setup screen. + [Mod] <js> Using the Goto Dialog updates channel parameters and sets the elapsed time now (http://bugs.openmpt.org/view.php?id=28). + [Mod] <js> Undo steps have been increased from 100 to 1000. + [Fix] <js> Shrink selection is more consistent with Shrink pattern now: Entries on odd rows are not ignored anymore if there is no entry in the even rows. Also, cleaning of the pattern after shrinking the selection has been fixed - it cleaned whole commands instead of just the selected parts of a command (http://bugs.openmpt.org/view.php?id=89). + [Fix] <js> Cursor paste was possible even when editing was disabled. + [Fix] <js> Using Right-Click -> Change Plugin on Parameter Control Events did not work for plugin numbers that were higher than the highest instrument number. + [Fix] <js> When entering chords into the pattern editor, the module was only marked as modified if the base note of the chord was changed. + [Fix] <js> When jumping to an order which is normally not played, the song variables are now reset. Previously, if the main song had e.g. a global volume fade out at the end, this was retained when switching to an unplayed order, effectively muting all sub songs. + [Fix] <js> OpenMPT does not crash anymore when applying the Amplify command on a pattern selection that just covers the note / instrument column of the first channel. + [Fix] <js> Queueing a "---" or "+++" item now automatically moves the queue "cursor" to the next available pattern. Previously, queueing a "---" pattern restarted the song. + [Fix] <js> Changing a channel name from the pattern editor didn't mark the document as modified (http://bugs.openmpt.org/view.php?id=65) + [Fix] <js> When restarting a pattern, the song timer was not reset properly. + [Fix] <js> Entering a note-off event in the MOD format created an unnecessary undo event. + [Fix] <js> Automation data is not written to the pattern if the current module format does not support smooth MIDI macros. + [Fix] <js> Selections were not clamped properly to the end of the pattern sometimes. + [Reg] <js> The "Position aware timer" option is gone. The position aware timer is now automatically used. It was optional in the first place because of some buggy code, which is now fixed. Pattern tab::Note properties - [Fix] <Jojo> The meaning of Q0x was displayed wrong for IT / S3M. - [Fix] <Jojo> Changing a value didn't create an undo point. (http://bugs.openmpt.org/view.php?id=56) - [Fix] <Jojo> Setting the PC note plugin didn't work. + [Fix] <js> Explanation of Q0x was wrong for IT / S3M. + [Fix] <js> Changing a value didn't create an undo point (http://bugs.openmpt.org/view.php?id=56). + [Fix] <js> Setting the Parameter Control Event plugin didn't work. -Pattern tab::Find/replace - [New] <Jojo> Added Find / Replace mode: Find in current pattern selection. (http://bugs.openmpt.org/view.php?id=42) - [Imp] <Jojo> When changing the content of a combobox, the corresponding checkbox is now automatically checked. Likewise, the "Replace By" checkbox is checked if a checkbox or combobox on the "Replace" tab is... [truncated message content] |
From: <sag...@us...> - 2012-05-06 20:50:30
|
Revision: 1265 http://modplug.svn.sourceforge.net/modplug/?rev=1265&view=rev Author: saga-games Date: 2012-05-06 20:50:23 +0000 (Sun, 06 May 2012) Log Message: ----------- [Fix] Pattern Editor: Fixed Shift+Click behaviour if a selection has already been made (http://bugs.openmpt.org/view.php?id=249). [Mod] Package Template: Added/moved files for zip package which were only present in installer package so far. Modified Paths: -------------- trunk/OpenMPT/installer/filetypes.iss trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_pat.h Added Paths: ----------- trunk/OpenMPT/packageTemplate/ModPlug Central.url trunk/OpenMPT/packageTemplate/mpt.ico Removed Paths: ------------- trunk/OpenMPT/installer/mpt.ico Modified: trunk/OpenMPT/installer/filetypes.iss =================================================================== --- trunk/OpenMPT/installer/filetypes.iss 2012-05-05 15:37:01 UTC (rev 1264) +++ trunk/OpenMPT/installer/filetypes.iss 2012-05-06 20:50:23 UTC (rev 1265) @@ -91,5 +91,5 @@ [Files] ; icon file (should be moved into EXE) -Source: "mpt.ico"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\packageTemplate\mpt.ico"; DestDir: "{app}"; Flags: ignoreversion Deleted: trunk/OpenMPT/installer/mpt.ico =================================================================== (Binary files differ) Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-05-05 15:37:01 UTC (rev 1264) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-05-06 20:50:23 UTC (rev 1265) @@ -1142,24 +1142,37 @@ m_bInItemRect = true; m_bShiftDragging = false; + PatternCursor pointCursor(GetPositionFromPoint(point)); + SetCapture(); - if ((point.x >= m_szHeader.cx) && (point.y <= m_szHeader.cy)) + if(point.x >= m_szHeader.cx && point.y <= m_szHeader.cy) { + // Click on channel header if (nFlags & MK_CONTROL) { - TogglePendingMute(GetPositionFromPoint(point).GetChannel()); + TogglePendingMute(pointCursor.GetChannel()); } - } - else if ((point.x >= m_szHeader.cx) && (point.y > m_szHeader.cy)) + } else if(point.x >= m_szHeader.cx && point.y > m_szHeader.cy) { - if(CMainFrame::GetInputHandler()->SelectionPressed() && m_StartSel == m_Selection.GetLowerRight()) + // Click on pattern data + + if(CMainFrame::GetInputHandler()->SelectionPressed() + && ((m_dwStatus & psShiftSelect) + || m_Selection.GetUpperLeft() == m_Selection.GetLowerRight() + || !m_Selection.Contains(pointCursor))) { // Shift pressed -> set 2nd selection point - DragToSel(GetPositionFromPoint(point), true, true); + // This behaviour is only used if: + // * Shift-click has previously been used since the shift key has been pressed down (psShiftSelect flag is set), + // * No selection has been made yet, or + // * Shift-clicking outside the current selection. + // This is necessary so that selections can still be moved properly while the shift button is pressed (for copy-move). + DragToSel(pointCursor, true, true); + m_dwStatus |= psShiftSelect; } else { // Set first selection point - m_StartSel = GetPositionFromPoint(point); + m_StartSel = pointCursor; if(m_StartSel.GetChannel() < pSndFile->GetNumChannels()) { m_dwStatus |= psMouseDragSelect; @@ -1183,20 +1196,19 @@ } } } - } else if((point.x < m_szHeader.cx) && (point.y > m_szHeader.cy)) + } else if(point.x < m_szHeader.cx && point.y > m_szHeader.cy) { // Mark row number => mark whole row (start) InvalidateSelection(); - PatternCursor cursor(GetPositionFromPoint(point)); - if(cursor.GetRow() < pSndFile->Patterns[m_nPattern].GetNumRows()) + if(pointCursor.GetRow() < pSndFile->Patterns[m_nPattern].GetNumRows()) { - m_StartSel.Set(cursor); - SetCurSel(cursor, PatternCursor(cursor.GetRow(), pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn)); + m_StartSel.Set(pointCursor); + SetCurSel(pointCursor, PatternCursor(pointCursor.GetRow(), pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn)); m_dwStatus |= psRowSelection; } } - if (m_nDragItem) + if(m_nDragItem) { InvalidateRect(&m_rcDragItem, FALSE); UpdateWindow(); @@ -1216,7 +1228,7 @@ return; } else { - if (ShowEditWindow()) return; + if(ShowEditWindow()) return; } } OnLButtonDown(uFlags, point); @@ -4075,13 +4087,15 @@ case kcSelectWithCopySelect: case kcSelectWithNav: case kcSelect: if (!(m_dwStatus & (psDragnDropEdit|psRowSelection))) m_StartSel = m_Cursor; - m_dwStatus |= psKeyboardDragSelect; return wParam; + m_dwStatus |= psKeyboardDragSelect; + return wParam; case kcSelectOffWithCopySelect: case kcSelectOffWithNav: - case kcSelectOff: m_dwStatus &= ~psKeyboardDragSelect; return wParam; + case kcSelectOff: m_dwStatus &= ~(psKeyboardDragSelect | psShiftSelect); + return wParam; case kcCopySelectWithSelect: case kcCopySelectWithNav: - case kcCopySelect: if (!(m_dwStatus & (psDragnDropEdit|psRowSelection))) m_StartSel = m_Cursor; + case kcCopySelect: if (!(m_dwStatus & (psDragnDropEdit | psRowSelection))) m_StartSel = m_Cursor; m_dwStatus |= psCtrlDragSelect; return wParam; case kcCopySelectOffWithSelect: case kcCopySelectOffWithNav: Modified: trunk/OpenMPT/mptrack/View_pat.h =================================================================== --- trunk/OpenMPT/mptrack/View_pat.h 2012-05-05 15:37:01 UTC (rev 1264) +++ trunk/OpenMPT/mptrack/View_pat.h 2012-05-06 20:50:23 UTC (rev 1265) @@ -105,23 +105,24 @@ { protected: + // Pattern status flags enum PatternStatus { - psMouseDragSelect = 0x01, // Creating a selection using the mouse - psKeyboardDragSelect = 0x02, // Creating a selection using shortcuts - psFocussed = 0x04, // Is the pattern editor focussed - psFollowSong = 0x08, // Does the cursor follow playback - psRecordingEnabled = 0x10, // Recording enabled - psDragHScroll = 0x20, // Some weird dragging stuff (?) - psDragVScroll = 0x40, // Some weird dragging stuff (?) - psShowVUMeters = 0x80, // Display channel VU meters? - psChordPlaying = 0x100, // Is a chord playing? (pretty much unused) - psDragnDropEdit = 0x200, // Drag & Drop editing (?) - psDragnDropping = 0x400, // Dragging a selection around - //psMIDISpacingPending = 0x800, // Unused (?) - psCtrlDragSelect = 0x1000, // Creating a selection using Ctrl - psShowPluginNames = 0x2000, // Show plugin names in channel headers //rewbs.patPlugName - psRowSelection = 0x4000, // Selecting a whole pattern row by clicking the row numbers + psMouseDragSelect = 0x01, // Creating a selection using the mouse + psKeyboardDragSelect = 0x02, // Creating a selection using shortcuts + psFocussed = 0x04, // Is the pattern editor focussed + psFollowSong = 0x08, // Does the cursor follow playback + psRecordingEnabled = 0x10, // Recording enabled + psDragHScroll = 0x20, // Some weird dragging stuff (?) - unused + psDragVScroll = 0x40, // Some weird dragging stuff (?) + psShowVUMeters = 0x80, // Display channel VU meters + psChordPlaying = 0x100, // Is a chord playing? (pretty much unused) + psDragnDropEdit = 0x200, // Drag & Drop editing (?) + psDragnDropping = 0x400, // Dragging a selection around + psShiftSelect = 0x800, // User has made at least one selection using Shift-Click since the Shift key has been pressed. + psCtrlDragSelect = 0x1000, // Creating a selection using Ctrl + psShowPluginNames = 0x2000, // Show plugin names in channel headers + psRowSelection = 0x4000, // Selecting a whole pattern row by clicking the row numbers }; CFastBitmap m_Dib; Added: trunk/OpenMPT/packageTemplate/ModPlug Central.url =================================================================== --- trunk/OpenMPT/packageTemplate/ModPlug Central.url (rev 0) +++ trunk/OpenMPT/packageTemplate/ModPlug Central.url 2012-05-06 20:50:23 UTC (rev 1265) @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=http://forum.openmpt.org/ Copied: trunk/OpenMPT/packageTemplate/mpt.ico (from rev 1262, trunk/OpenMPT/installer/mpt.ico) =================================================================== (Binary files differ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-10 16:26:39
|
Revision: 1266 http://modplug.svn.sourceforge.net/modplug/?rev=1266&view=rev Author: saga-games Date: 2012-05-10 16:26:32 +0000 (Thu, 10 May 2012) Log Message: ----------- Refactoring in your general direction. Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_pat.cpp trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp trunk/OpenMPT/mptrack/Mainfrm.h trunk/OpenMPT/mptrack/Stdafx.h trunk/OpenMPT/mptrack/Undo.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/tagging.cpp trunk/OpenMPT/mptrack/tagging.h trunk/OpenMPT/soundlib/Endianness.h trunk/OpenMPT/soundlib/ITTools.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_okt.cpp trunk/OpenMPT/soundlib/ModSample.cpp trunk/OpenMPT/soundlib/ModSample.h trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/Ctrl_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -240,23 +240,23 @@ { CHAR s[256]; m_OrderList.UpdateView(dwHintMask, pObj); - if (!m_pSndFile) return; + if(!m_pSndFile) return; - if (dwHintMask & HINT_MODSEQUENCE) + if(dwHintMask & HINT_MODSEQUENCE) { SetDlgItemText(IDC_EDIT_SEQUENCE_NAME, m_pSndFile->Order.m_sName); } - if (dwHintMask & (HINT_MODSEQUENCE|HINT_MODTYPE)) + if(dwHintMask & (HINT_MODSEQUENCE|HINT_MODTYPE)) { m_SpinSequence.SetRange(0, m_pSndFile->Order.GetNumSequences() - 1); m_SpinSequence.SetPos(m_pSndFile->Order.GetCurrentSequenceIndex()); } //rewbs.instroVST - if (dwHintMask & (HINT_MIXPLUGINS|HINT_MODTYPE)) + if(dwHintMask & (HINT_MIXPLUGINS|HINT_MODTYPE)) { if (HasValidPlug(m_nInstrument)) - ::EnableWindow(::GetDlgItem(m_hWnd, IDC_PATINSTROPLUGGUI), true); + ::EnableWindow(::GetDlgItem(m_hWnd, IDC_PATINSTROPLUGGUI), true); else ::EnableWindow(::GetDlgItem(m_hWnd, IDC_PATINSTROPLUGGUI), false); @@ -273,7 +273,7 @@ GetDlgItem(IDC_EDIT_PATTERNNAME)->EnableWindow(isPatNameAvail); } //end rewbs.instroVST - if (dwHintMask & HINT_MPTOPTIONS) + if(dwHintMask & HINT_MPTOPTIONS) { m_ToolBar.UpdateStyle(); // -> CODE#0007 @@ -282,10 +282,10 @@ m_ToolBar.SetState(ID_OVERFLOWPASTE, ((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_OVERFLOWPASTE) ? TBSTATE_CHECKED : 0) | TBSTATE_ENABLED); // -! BEHAVIOUR_CHANGE#0007 } - if (dwHintMask & (HINT_MODTYPE|HINT_INSNAMES|HINT_SMPNAMES|HINT_PATNAMES)) + if(dwHintMask & (HINT_MODTYPE|HINT_INSNAMES|HINT_SMPNAMES|HINT_PATNAMES)) { LockControls(); - if (dwHintMask & (HINT_MODTYPE|HINT_INSNAMES|HINT_SMPNAMES)) + if(dwHintMask & (HINT_MODTYPE|HINT_INSNAMES|HINT_SMPNAMES)) { static const TCHAR szSplitFormat[] = TEXT("%02u %s %02u: %s/%s"); UINT nPos = 0; @@ -295,12 +295,12 @@ const INSTRUMENTINDEX nSplitIns = m_pModDoc->GetSplitKeyboardSettings().splitInstrument; const ModCommand::NOTE noteSplit = 1 + m_pModDoc->GetSplitKeyboardSettings().splitNote; const CString sSplitInsName = m_pModDoc->GetPatternViewInstrumentName(nSplitIns, true, false); - if (m_pSndFile->GetNumInstruments()) + if(m_pSndFile->GetNumInstruments()) { // Show instrument names - for (INSTRUMENTINDEX i = 1; i <= m_pSndFile->GetNumInstruments(); i++) + for(INSTRUMENTINDEX i = 1; i <= m_pSndFile->GetNumInstruments(); i++) { - if (m_pSndFile->Instruments[i] == nullptr) + if(m_pSndFile->Instruments[i] == nullptr) continue; CString sDisplayName; @@ -314,14 +314,14 @@ sDisplayName = m_pModDoc->GetPatternViewInstrumentName(i); UINT n = m_CbnInstrument.AddString(sDisplayName); - if (n == m_nInstrument) nPos = n; + if(n == m_nInstrument) nPos = n; m_CbnInstrument.SetItemData(n, i); } } else { // Show sample names SAMPLEINDEX nmax = m_pSndFile->GetNumSamples(); - for (SAMPLEINDEX i = 1; i <= nmax; i++) if (m_pSndFile->GetSample(i).pSample) + for(SAMPLEINDEX i = 1; i <= nmax; i++) if (m_pSndFile->GetSample(i).pSample) { if (m_pModDoc->GetSplitKeyboardSettings().IsSplitActive()) wsprintf(s, szSplitFormat, nSplitIns, GetNoteStr(noteSplit), i, m_pSndFile->m_szNames[nSplitIns], m_pSndFile->m_szNames[i]); @@ -329,23 +329,24 @@ wsprintf(s, "%02u: %s", i, m_pSndFile->m_szNames[i]); UINT n = m_CbnInstrument.AddString(s); - if (n == m_nInstrument) nPos = n; + if(n == m_nInstrument) nPos = n; m_CbnInstrument.SetItemData(n, i); } } m_CbnInstrument.SetCurSel(nPos); m_CbnInstrument.SetRedraw(TRUE); } - if (dwHintMask & (HINT_MODTYPE|HINT_PATNAMES)) + if(dwHintMask & (HINT_MODTYPE|HINT_PATNAMES)) { PATTERNINDEX nPat; - if (dwHintMask & HINT_PATNAMES) + if(dwHintMask & HINT_PATNAMES) nPat = (PATTERNINDEX)(dwHintMask >> HINT_SHIFT_PAT); else nPat = (PATTERNINDEX)SendViewMessage(VIEWMSG_GETCURRENTPATTERN); m_pSndFile->Patterns[nPat].GetName(s, CountOf(s)); m_EditPatName.SetWindowText(s); - BOOL bXMIT = (m_pSndFile->m_nType & (MOD_TYPE_XM|MOD_TYPE_IT|MOD_TYPE_MPT)) ? TRUE : FALSE; + + BOOL bXMIT = (m_pSndFile->GetType() & (MOD_TYPE_XM|MOD_TYPE_IT|MOD_TYPE_MPT)) ? TRUE : FALSE; m_ToolBar.EnableButton(ID_PATTERN_MIDIMACRO, bXMIT); m_ToolBar.EnableButton(ID_PATTERN_PROPERTIES, bXMIT); m_ToolBar.EnableButton(ID_PATTERN_EXPAND, bXMIT); @@ -483,18 +484,22 @@ break; } - bool setLoop = false; - if (lParam == -1) { + bool setLoop = false; + if (lParam == -1) + { //Toggle loop state setLoop = !(m_pSndFile->m_dwSongFlags&SONG_PATTERNLOOP); - } else { + } else + { setLoop = (lParam != 0); } - if (setLoop) { + if (setLoop) + { m_pSndFile->m_dwSongFlags |= SONG_PATTERNLOOP; CheckDlgButton(IDC_PATTERN_LOOP, BST_CHECKED); - } else { + } else + { m_pSndFile->m_dwSongFlags &= ~SONG_PATTERNLOOP; CheckDlgButton(IDC_PATTERN_LOOP, BST_UNCHECKED); } @@ -746,7 +751,7 @@ SwitchToView(); //rewbs.instroVST if (HasValidPlug(m_nInstrument)) - ::EnableWindow(::GetDlgItem(m_hWnd, IDC_PATINSTROPLUGGUI), true); + ::EnableWindow(::GetDlgItem(m_hWnd, IDC_PATINSTROPLUGGUI), true); else ::EnableWindow(::GetDlgItem(m_hWnd, IDC_PATINSTROPLUGGUI), false); //rewbs.instroVST Modified: trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp =================================================================== --- trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -66,8 +66,7 @@ LRESULT CMIDIMappingDialog::OnMidiMsg(WPARAM dwMidiDataParam, LPARAM) //------------------------------------------------------------------- { - const BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiDataParam); - if(event == 0xB && IsDlgButtonChecked(IDC_CHECK_MIDILEARN)) + if(MIDIEvents::GetTypeFromEvent(dwMidiDataParam) == MIDIEvents::evControllerChange && IsDlgButtonChecked(IDC_CHECK_MIDILEARN)) { m_ChannelCBox.SetCurSel(1 + MIDIEvents::GetChannelFromEvent(dwMidiDataParam)); m_EventCBox.SetCurSel(0); Modified: trunk/OpenMPT/mptrack/Mainfrm.h =================================================================== --- trunk/OpenMPT/mptrack/Mainfrm.h 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/Mainfrm.h 2012-05-10 16:26:32 UTC (rev 1266) @@ -208,7 +208,6 @@ #define MIDISETUP_MIDIVOL_TO_NOTEVOL 0x08 // Combine MIDI volume to note velocity #define MIDISETUP_RECORDNOTEOFF 0x10 // Record MIDI Note Off to pattern #define MIDISETUP_RESPONDTOPLAYCONTROLMSGS 0x20 // Respond to Restart/Continue/Stop MIDI commands -#define MIDISETUP_AMPLIFYVELOCITY 0x40 // Amplify velocity of recorded notes #define MIDISETUP_MIDIMACROCONTROL 0x80 // Record MIDI controller changes a MIDI macro changes in pattern #define MIDISETUP_PLAYPATTERNONMIDIIN 0x100 // Play pattern if MIDI Note is received and playback is paused @@ -656,7 +655,7 @@ DECLARE_MESSAGE_MAP() public: afx_msg void OnInitMenu(CMenu* pMenu); - bool UpdateEffectKeys(void); + bool UpdateEffectKeys(); afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); Modified: trunk/OpenMPT/mptrack/Stdafx.h =================================================================== --- trunk/OpenMPT/mptrack/Stdafx.h 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/Stdafx.h 2012-05-10 16:26:32 UTC (rev 1266) @@ -98,6 +98,7 @@ #include "../common/typedefs.h" // Exception type that is used to catch "operator new" exceptions. +//typedef std::bad_alloc & MPTMemoryException; typedef CMemoryException * MPTMemoryException; //To mark string that should be translated in case of multilingual version. Modified: trunk/OpenMPT/mptrack/Undo.cpp =================================================================== --- trunk/OpenMPT/mptrack/Undo.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/Undo.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -365,68 +365,68 @@ bool CSampleUndo::Undo(const SAMPLEINDEX nSmp) //-------------------------------------------- { - if(m_pModDoc == nullptr || CanUndo(nSmp) == false) return false; + if(m_pModDoc == nullptr || !CanUndo(nSmp)) return false; CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); if(pSndFile == nullptr) return false; // Select most recent undo slot - SAMPLEUNDOBUFFER *pUndo = &UndoBuffer[nSmp - 1].back(); + SAMPLEUNDOBUFFER &undo = UndoBuffer[nSmp - 1].back(); ModSample &sample = pSndFile->GetSample(nSmp); LPSTR pCurrentSample = sample.pSample; LPSTR pNewSample = nullptr; // a new sample is possibly going to be allocated, depending on what's going to be undone. - UINT nBytesPerSample = pUndo->OldSample.GetBytesPerSample(); - UINT nChangeLen = pUndo->nChangeEnd - pUndo->nChangeStart; + UINT nBytesPerSample = undo.OldSample.GetBytesPerSample(); + UINT nChangeLen = undo.nChangeEnd - undo.nChangeStart; - switch(pUndo->nChangeType) + switch(undo.nChangeType) { case sundo_none: break; case sundo_invert: // invert again - ctrlSmp::InvertSample(sample, pUndo->nChangeStart, pUndo->nChangeEnd, pSndFile); + ctrlSmp::InvertSample(sample, undo.nChangeStart, undo.nChangeEnd, pSndFile); break; case sundo_reverse: // reverse again - ctrlSmp::ReverseSample(sample, pUndo->nChangeStart, pUndo->nChangeEnd, pSndFile); + ctrlSmp::ReverseSample(sample, undo.nChangeStart, undo.nChangeEnd, pSndFile); break; case sundo_unsign: // unsign again - ctrlSmp::UnsignSample(sample, pUndo->nChangeStart, pUndo->nChangeEnd, pSndFile); + ctrlSmp::UnsignSample(sample, undo.nChangeStart, undo.nChangeEnd, pSndFile); break; case sundo_insert: // delete inserted data - ASSERT(nChangeLen == sample.nLength - pUndo->OldSample.nLength); - memcpy(pCurrentSample + pUndo->nChangeStart * nBytesPerSample, pCurrentSample + pUndo->nChangeEnd * nBytesPerSample, (sample.nLength - pUndo->nChangeEnd) * nBytesPerSample); + ASSERT(nChangeLen == sample.nLength - undo.OldSample.nLength); + memcpy(pCurrentSample + undo.nChangeStart * nBytesPerSample, pCurrentSample + undo.nChangeEnd * nBytesPerSample, (sample.nLength - undo.nChangeEnd) * nBytesPerSample); // also clean the sample end - memset(pCurrentSample + pUndo->OldSample.nLength * nBytesPerSample, 0, (sample.nLength - pUndo->OldSample.nLength) * nBytesPerSample); + memset(pCurrentSample + undo.OldSample.nLength * nBytesPerSample, 0, (sample.nLength - undo.OldSample.nLength) * nBytesPerSample); break; case sundo_update: // simply replace what has been updated. - if(sample.nLength < pUndo->nChangeEnd) return false; - memcpy(pCurrentSample + pUndo->nChangeStart * nBytesPerSample, pUndo->SamplePtr, nChangeLen * nBytesPerSample); + if(sample.nLength < undo.nChangeEnd) return false; + memcpy(pCurrentSample + undo.nChangeStart * nBytesPerSample, undo.SamplePtr, nChangeLen * nBytesPerSample); break; case sundo_delete: // insert deleted data - pNewSample = pSndFile->AllocateSample(pUndo->OldSample.GetSampleSizeInBytes() + 4 * nBytesPerSample); + pNewSample = pSndFile->AllocateSample(undo.OldSample.GetSampleSizeInBytes() + 4 * nBytesPerSample); if(pNewSample == nullptr) return false; - memcpy(pNewSample, pCurrentSample, pUndo->nChangeStart * nBytesPerSample); - memcpy(pNewSample + pUndo->nChangeStart * nBytesPerSample, pUndo->SamplePtr, nChangeLen * nBytesPerSample); - memcpy(pNewSample + pUndo->nChangeEnd * nBytesPerSample, pCurrentSample + pUndo->nChangeStart * nBytesPerSample, (pUndo->OldSample.nLength - pUndo->nChangeEnd) * nBytesPerSample); + memcpy(pNewSample, pCurrentSample, undo.nChangeStart * nBytesPerSample); + memcpy(pNewSample + undo.nChangeStart * nBytesPerSample, undo.SamplePtr, nChangeLen * nBytesPerSample); + memcpy(pNewSample + undo.nChangeEnd * nBytesPerSample, pCurrentSample + undo.nChangeStart * nBytesPerSample, (undo.OldSample.nLength - undo.nChangeEnd) * nBytesPerSample); break; case sundo_replace: // simply exchange sample pointer - pNewSample = pUndo->SamplePtr; - pUndo->SamplePtr = nullptr; // prevent sample from being deleted + pNewSample = undo.SamplePtr; + undo.SamplePtr = nullptr; // prevent sample from being deleted break; default: @@ -435,13 +435,13 @@ } // Restore old sample header - MemCopy(sample, pUndo->OldSample); + MemCopy(sample, undo.OldSample); sample.pSample = pCurrentSample; // select the "correct" old sample - MemCopy(pSndFile->m_szNames[nSmp], pUndo->szOldName); + MemCopy(pSndFile->m_szNames[nSmp], undo.szOldName); if(pNewSample != nullptr) { - ctrlSmp::ReplaceSample(sample, pNewSample, pUndo->OldSample.nLength, pSndFile); + ctrlSmp::ReplaceSample(sample, pNewSample, undo.OldSample.nLength, pSndFile); } ctrlSmp::AdjustEndOfSample(sample, pSndFile); Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -2392,7 +2392,7 @@ // Specific Note Off if (note > NOTE_KEYOFF) //rewbs.vstiLive { - note--; + note -= NOTE_MIN; uint8 i = static_cast<uint8>(note - NOTE_KEYOFF); if(channel.uNoteOnMap[i][trackChannel]) { @@ -2470,7 +2470,7 @@ bool CVstPlugin::isPlaying(UINT note, UINT midiChn, UINT trackerChn) //------------------------------------------------------------------ { - note--; + note -= NOTE_MIN; return (m_MidiCh[midiChn].uNoteOnMap[note][trackerChn] != 0); } @@ -2478,7 +2478,7 @@ bool CVstPlugin::MoveNote(UINT note, UINT midiChn, UINT sourceTrackerChn, UINT destTrackerChn) //--------------------------------------------------------------------------------------------- { - note--; + note -= NOTE_MIN; VSTInstrChannel *pMidiCh = &m_MidiCh[midiChn & 0x0f]; if (!(pMidiCh->uNoteOnMap[note][sourceTrackerChn])) Modified: trunk/OpenMPT/mptrack/tagging.cpp =================================================================== --- trunk/OpenMPT/mptrack/tagging.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/tagging.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -29,16 +29,17 @@ // Convert Integer to Synchsafe Integer (see ID3v2.4 specs) // Basically, it's a BigEndian integer, but the MSB of all bytes is 0. // Thus, a 32-bit integer turns into a 28-bit integer. -uint32 CFileTagging::intToSynchsafe(uint32 iIn) -//--------------------------------------------- +uint32 CFileTagging::intToSynchsafe(uint32 in) +//-------------------------------------------- { - uint32 iOut = 0, iSteps = 0; + uint32 out = 0, steps = 0; do { - iOut |= (iIn & 0x7F) << iSteps; - iSteps += 8; - } while(iIn >>= 7); - return BigEndian(iOut); + out |= (in & 0x7F) << steps; + steps += 8; + } while(in >>= 7); + SwapBytesBE(out); + return out; } // Write Tags Modified: trunk/OpenMPT/mptrack/tagging.h =================================================================== --- trunk/OpenMPT/mptrack/tagging.h 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/mptrack/tagging.h 2012-05-10 16:26:32 UTC (rev 1266) @@ -116,7 +116,7 @@ private: // Convert Integer to Synchsafe Integer (see ID3v2.4 specs) - uint32 intToSynchsafe(UINT32 in); + uint32 intToSynchsafe(uint32 in); // Write a frame void WriteID3v2Frame(char cFrameID[4], string sFramecontent, FILE *f); // Size of our tag Modified: trunk/OpenMPT/soundlib/Endianness.h =================================================================== --- trunk/OpenMPT/soundlib/Endianness.h 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/Endianness.h 2012-05-10 16:26:32 UTC (rev 1266) @@ -36,23 +36,23 @@ #ifdef PLATFORM_BIG_ENDIAN // PPC -inline void SwapBytesBE(uint32 &value) { value; } -inline void SwapBytesBE(uint16 &value) { value; } -inline void SwapBytesLE(uint32 &value) { value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); } -inline void SwapBytesLE(uint16 &value) { value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)); } -inline void SwapBytesBE(int32 &value) { value; } -inline void SwapBytesBE(int16 &value) { value; } -inline void SwapBytesLE(int32 &value) { value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); } -inline void SwapBytesLE(int16 &value) { value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)); } +inline uint32 SwapBytesBE(uint32 &value) { return value; } +inline uint16 SwapBytesBE(uint16 &value) { return value; } +inline uint32 SwapBytesLE(uint32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } +inline uint16 SwapBytesLE(uint16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)); } +inline int32 SwapBytesBE(int32 &value) { return value; } +inline int16 SwapBytesBE(int16 &value) { return value; } +inline int32 SwapBytesLE(int32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } +inline int16 SwapBytesLE(int16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00))); } #else // x86 -inline void SwapBytesBE(uint32 &value) { value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); } -inline void SwapBytesBE(uint16 &value) { value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)); } -inline void SwapBytesLE(uint32 &value) { value; } -inline void SwapBytesLE(uint16 &value) { value; } -inline void SwapBytesBE(int32 &value) { value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); } -inline void SwapBytesBE(int16 &value) { value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)); } -inline void SwapBytesLE(int32 &value) { value; } -inline void SwapBytesLE(int16 &value) { value; } +inline uint32 SwapBytesBE(uint32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } +inline uint16 SwapBytesBE(uint16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00))); } +inline uint32 SwapBytesLE(uint32 &value) { return value; } +inline uint16 SwapBytesLE(uint16 &value) { return value; } +inline int32 SwapBytesBE(int32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } +inline int16 SwapBytesBE(int16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00))); } +inline int32 SwapBytesLE(int32 &value) { return value; } +inline int16 SwapBytesLE(int16 &value) { return value; } #endif Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -198,8 +198,8 @@ // Volume / Panning fadeout = LittleEndianW(static_cast<uint16>(min(mptIns.nFadeOut >> 5, 256))); - gbv = static_cast<uint8>(mptIns.nGlobalVol * 2); - dfp = static_cast<uint8>(mptIns.nPan >> 2); + gbv = static_cast<uint8>(min(mptIns.nGlobalVol * 2, 128)); + dfp = static_cast<uint8>(min(mptIns.nPan / 4, 64)); if(!(mptIns.dwFlags & INS_SETPANNING)) dfp |= ITInstrument::ignorePanning; // Random Variation @@ -281,7 +281,7 @@ mptIns.nFadeOut = LittleEndianW(fadeout) << 5; mptIns.nGlobalVol = gbv / 2; LimitMax(mptIns.nGlobalVol, 64u); - mptIns.nPan = (dfp & 0x7F) << 2; + mptIns.nPan = (dfp & 0x7F) * 4; if(mptIns.nPan > 256) mptIns.nPan = 128; if(!(dfp & ITInstrument::ignorePanning)) mptIns.dwFlags |= INS_SETPANNING; Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -896,19 +896,24 @@ #endif // Writing instruments - for(SAMPLEINDEX smp = 1; smp <= 31; smp++) if (sampleLength[smp]) + for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { + if(sampleLength[smp] == 0) + { + continue; + } const ModSample &sample = Samples[sampleSource[smp]]; const long sampleStart = ftell(f); const UINT writtenBytes = WriteSample(f, &sample, RS_PCM8S, sampleLength[smp]); + static const int8 silence[] = {0, 0}; + if((sample.uFlags & CHN_LOOP) == 0) { // First two bytes of oneshot samples have to be 0 due to PT's one-shot loop const long sampleEnd = ftell(f); fseek(f, sampleStart, SEEK_SET); - int8 silence[] = {0, 0}; fwrite(&silence, min(writtenBytes, 2), 1, f); fseek(f, sampleEnd, SEEK_SET); } @@ -916,8 +921,7 @@ // Write padding byte if the sample size is odd. if((sample.nLength % 2) != 0) { - int8 padding = 0; - fwrite(&padding, 1, 1, f); + fwrite(&silence[0], 1, 1, f); } } Modified: trunk/OpenMPT/soundlib/Load_okt.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_okt.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/Load_okt.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -428,7 +428,7 @@ SmpLength i = mptSample.nLength; while(i--) { - *data = Clamp(*data * 2, int8(-128), int8(127)); + *data = static_cast<uint8>(Clamp(static_cast<int>(*data) * 2, int8(-128), int8(127))); *data++; } } Modified: trunk/OpenMPT/soundlib/ModSample.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSample.cpp 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/ModSample.cpp 2012-05-10 16:26:32 UTC (rev 1266) @@ -88,3 +88,15 @@ } } } + + +uint32 ModSample::GetSampleRate(const MODTYPE type) const +//------------------------------------------------------- +{ + uint32 rate; + if(type & (MOD_TYPE_MOD | MOD_TYPE_XM)) + rate = CSoundFile::TransposeToFrequency(RelativeTone, nFineTune); + else + rate = nC5Speed; + return (rate > 0) ? rate : 8363; +} Modified: trunk/OpenMPT/soundlib/ModSample.h =================================================================== --- trunk/OpenMPT/soundlib/ModSample.h 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/ModSample.h 2012-05-10 16:26:32 UTC (rev 1266) @@ -40,7 +40,7 @@ uint8 GetBytesPerSample() const { return GetElementarySampleSize() * GetNumChannels(); } // Return the size which pSample is at least. - DWORD GetSampleSizeInBytes() const { return nLength * GetBytesPerSample(); } + SmpLength GetSampleSizeInBytes() const { return nLength * GetBytesPerSample(); } // Returns sample rate of the sample. The argument is needed because // the sample rate is obtained differently for different module types. Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-05-06 20:50:23 UTC (rev 1265) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-05-10 16:26:32 UTC (rev 1266) @@ -742,18 +742,6 @@ #pragma warning(default : 4324) //structure was padded due to __declspec(align()) -inline uint32 ModSample::GetSampleRate(const MODTYPE type) const -//-------------------------------------------------------------- -{ - uint32 nRate; - if(type & (MOD_TYPE_MOD|MOD_TYPE_XM)) - nRate = CSoundFile::TransposeToFrequency(RelativeTone, nFineTune); - else - nRate = nC5Speed; - return (nRate > 0) ? nRate : 8363; -} - - inline IMixPlugin* CSoundFile::GetInstrumentPlugin(INSTRUMENTINDEX instr) //----------------------------------------------------------------------- { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-13 20:04:20
|
Revision: 1268 http://modplug.svn.sourceforge.net/modplug/?rev=1268&view=rev Author: saga-games Date: 2012-05-13 20:04:12 +0000 (Sun, 13 May 2012) Log Message: ----------- [Fix] Pattern Editor: Moving channels through drag&drop didn't update the channel names properly. [Fix] Sample Editor: Shouldn't crash anymore when cleaning up Undo RAM (http://bugs.openmpt.org/view.php?id=232). [Fix] IT Loading: Loading IT files made with older versions of OpenMPT replaces SC0 with ^^ instead of v00 now. [Mod] OpenMPT: Version is now 1.20.01.02 Modified Paths: -------------- trunk/OpenMPT/mptrack/Undo.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Sndfile.cpp Modified: trunk/OpenMPT/mptrack/Undo.cpp =================================================================== --- trunk/OpenMPT/mptrack/Undo.cpp 2012-05-10 16:31:50 UTC (rev 1267) +++ trunk/OpenMPT/mptrack/Undo.cpp 2012-05-13 20:04:12 UTC (rev 1268) @@ -490,12 +490,12 @@ UINT nCapacity = GetUndoBufferCapacity(); while(nCapacity > CMainFrame::GetSettings().m_nSampleUndoMaxBuffer) { - for(SAMPLEINDEX nSmp = 1; nSmp <= UndoBuffer.size(); nSmp++) + for(SAMPLEINDEX smp = 1; smp <= UndoBuffer.size(); smp++) { - if(UndoBuffer[nSmp - 1][0].SamplePtr != nullptr) + if(UndoBuffer[smp - 1].size() != 0 && UndoBuffer[smp - 1][0].SamplePtr != nullptr) { - nCapacity -= (UndoBuffer[nSmp - 1][0].nChangeEnd - UndoBuffer[nSmp - 1][0].nChangeStart) * UndoBuffer[nSmp - 1][0].OldSample.GetBytesPerSample(); - DeleteUndoStep(nSmp, 0); + nCapacity -= (UndoBuffer[smp - 1][0].nChangeEnd - UndoBuffer[smp - 1][0].nChangeStart) * UndoBuffer[smp - 1][0].OldSample.GetBytesPerSample(); + DeleteUndoStep(smp, 0); } if(nCapacity <= CMainFrame::GetSettings().m_nSampleUndoMaxBuffer) return; } Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-05-10 16:31:50 UTC (rev 1267) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-05-13 20:04:12 UTC (rev 1268) @@ -1341,7 +1341,7 @@ pModDoc->UpdateAllViews(this, HINT_MODCHANNELS | HINT_MODTYPE); SetCurrentPattern(m_nPattern); } - InvalidatePattern(); + InvalidatePattern(true); pModDoc->SetModified(); } } Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-05-10 16:31:50 UTC (rev 1267) +++ trunk/OpenMPT/mptrack/version.h 2012-05-13 20:04:12 UTC (rev 1268) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 01 +#define VER_MINORMINOR 02 //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/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-10 16:31:50 UTC (rev 1267) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-13 20:04:12 UTC (rev 1268) @@ -891,20 +891,30 @@ LPSTR CSoundFile::AllocateSample(UINT nbytes) //------------------------------------------- { - if (nbytes>0xFFFFFFD6) - return NULL; - LPSTR p = (LPSTR)GlobalAllocPtr(GHND, (nbytes+39) & ~7); - if (p) p += 16; - return p; + if (nbytes > 0xFFFFFFD6) + return nullptr; + + // Allocate with some overhead (16 bytes before sample start, and at least 16 bytes after that) + const size_t allocSize = (nbytes + 39) & ~7; + + try + { + LPSTR p = (LPSTR)new char[allocSize]; + memset(p, 0, allocSize); + return (p + 16); + } catch(MPTMemoryException) + { + return nullptr; + } } -void CSoundFile::FreeSample(LPVOID p) -//----------------------------------- +void CSoundFile::FreeSample(void *p) +//---------------------------------- { if (p) { - GlobalFreePtr(((LPSTR)p)-16); + delete[] (((char *)p) - 16); } } @@ -2800,8 +2810,7 @@ if(m.param == 0xC0) { m.command = CMD_NONE; - m.volcmd = VOLCMD_VOLUME; - m.vol = 0; + m.note = NOTE_NOTECUT; } else if(m.param == 0xD0) { m.command = CMD_NONE; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-14 21:50:19
|
Revision: 1269 http://modplug.svn.sourceforge.net/modplug/?rev=1269&view=rev Author: saga-games Date: 2012-05-14 21:50:12 +0000 (Mon, 14 May 2012) Log Message: ----------- [Ref] Moved InitializeSample to ModSample::Initialize. Modified Paths: -------------- trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Moddoc.h trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/soundlib/ITTools.cpp trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/ModSample.cpp trunk/OpenMPT/soundlib/ModSample.h trunk/OpenMPT/soundlib/ModSequence.cpp trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/XMTools.cpp Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -733,7 +733,7 @@ ctrlSmp::ResetSamples(m_SndFile, ctrlSmp::SmpResetInit); - InitializeSample(m_SndFile.GetSample(1)); + m_SndFile.GetSample(1).Initialize(m_SndFile.GetType()); if ((!m_SndFile.m_nInstruments) && (m_SndFile.GetType() & MOD_TYPE_XM)) { Modified: trunk/OpenMPT/mptrack/Moddoc.h =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.h 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/mptrack/Moddoc.h 2012-05-14 21:50:12 UTC (rev 1269) @@ -241,7 +241,6 @@ SAMPLEINDEX InsertSample(bool bLimit = false); INSTRUMENTINDEX InsertInstrument(SAMPLEINDEX lSample = SAMPLEINDEX_INVALID, INSTRUMENTINDEX lDuplicate = INSTRUMENTINDEX_INVALID); void InitializeInstrument(ModInstrument *pIns); - void InitializeSample(ModSample &sample); bool RemoveOrder(SEQUENCEINDEX nSeq, ORDERINDEX nOrd); bool RemovePattern(PATTERNINDEX nPat); bool RemoveSample(SAMPLEINDEX nSmp); Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -448,7 +448,7 @@ } if (!m_SndFile.m_szNames[i][0]) strcpy(m_SndFile.m_szNames[i], "untitled"); if (i > m_SndFile.GetNumSamples()) m_SndFile.m_nSamples = i; - InitializeSample(m_SndFile.GetSample(i)); + m_SndFile.GetSample(i).Initialize(m_SndFile.GetType()); SetModified(); return i; } @@ -554,27 +554,6 @@ } -void CModDoc::InitializeSample(ModSample &sample) -//----------------------------------------------- -{ - sample.nVolume = 256; - sample.nGlobalVol = 64; - sample.nPan = 128; - sample.nC5Speed = 8363; - sample.RelativeTone = 0; - sample.nFineTune = 0; - sample.nVibType = VIB_SINE; - sample.nVibSweep = 0; - sample.nVibDepth = 0; - sample.nVibRate = 0; - sample.uFlags &= ~(CHN_PANNING|CHN_SUSTAINLOOP|CHN_LOOP); - if(m_SndFile.GetType() == MOD_TYPE_XM) - { - sample.uFlags |= CHN_PANNING; - } -} - - // Load default instrument values for inserting new instrument during editing void CModDoc::InitializeInstrument(ModInstrument *pIns) //----------------------------------------------------- Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -499,10 +499,9 @@ return 0; } + mptSmp.Initialize(MOD_TYPE_IT); StringFixer::ReadString<StringFixer::nullTerminated>(mptSmp.filename, filename); - mptSmp.uFlags = 0; - // Volume / Panning mptSmp.nVolume = vol * 4; LimitMax(mptSmp.nVolume, WORD(256)); Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -98,7 +98,7 @@ }; #pragma pack(pop) -static BYTE imfEffects[] = +static const uint8 imfEffects[] = { CMD_NONE, CMD_SPEED, // 0x01 1xx Set Tempo @@ -539,6 +539,7 @@ ModSample &sample = Samples[firstsample + nSmp]; + sample.Initialize(); StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, imfsmp.filename); strcpy(m_szNames[m_nSamples], sample.filename); @@ -547,7 +548,6 @@ sample.nLoopEnd = LittleEndian(imfsmp.loop_end); sample.nC5Speed = LittleEndian(imfsmp.C5Speed); sample.nVolume = imfsmp.volume * 4; - sample.nGlobalVol = 256; sample.nPan = imfsmp.panning; if(imfsmp.flags & 1) sample.uFlags |= CHN_LOOP; Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -227,13 +227,10 @@ // Convert an MOD sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { - mptSmp.uFlags = 0; + mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = length * 2; - mptSmp.RelativeTone = 0; mptSmp.nFineTune = MOD2XMFineTune(finetune & 0x0F); mptSmp.nVolume = 4 * min(volume, 64); - mptSmp.nGlobalVol = 64; - mptSmp.nPan = 128; SmpLength lStart = loopStart * 2; SmpLength lLength = loopLength * 2; Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -174,6 +174,7 @@ trkImpulseTracker = 0x3000, trkSchismTracker = 0x4000, trkOpenMPT = 0x5000, + trkBeRoTracker = 0x6000, // Note: BeRoTracker also used version 0x4100 since 2004. trkST3_20 = 0x1320, trkIT2_14 = 0x3214, @@ -288,6 +289,7 @@ // Convert an S3M sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { + mptSmp.Initialize(MOD_TYPE_S3M); StringFixer::ReadString<StringFixer::maybeNullTerminated>(mptSmp.filename, filename); if((sampleType == typePCM || sampleType == typeNone) && magic == idSCRS) @@ -299,11 +301,6 @@ 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) @@ -314,8 +311,6 @@ // Volume / Panning mptSmp.nVolume = min(defaultVolume, 64) * 4; - mptSmp.nGlobalVol = 64; - mptSmp.nPan = 128; // C-5 frequency mptSmp.nC5Speed = c5speed; @@ -443,7 +438,7 @@ if((fileHeader.cwtv & S3MFileHeader::trackerMask) > S3MFileHeader::trkScreamTracker) { - // 2xyy - Imago Orpheus, 3xyy - IT, 4xyy - Schism, 5xyy - OpenMPT + // 2xyy - Imago Orpheus, 3xyy - IT, 4xyy - Schism, 5xyy - OpenMPT, 6xyy - BeRoTracker 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) Modified: trunk/OpenMPT/soundlib/ModSample.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSample.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/ModSample.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -90,6 +90,33 @@ } +// Initialize sample slot with default values. +void ModSample::Initialize(MODTYPE type) +//-------------------------------------- +{ + nLength = 0; + nLoopStart = nLoopEnd = 0; + nSustainStart = nSustainEnd = 0; + nVolume = 256; + nGlobalVol = 64; + nPan = 128; + nC5Speed = 8363; + RelativeTone = 0; + nFineTune = 0; + nVibType = VIB_SINE; + nVibSweep = 0; + nVibDepth = 0; + nVibRate = 0; + uFlags &= ~(CHN_PANNING | CHN_SUSTAINLOOP | CHN_LOOP); + if(type == MOD_TYPE_XM) + { + uFlags |= CHN_PANNING; + } + filename[0] = '\0'; +} + + +// Returns sample rate of the sample. uint32 ModSample::GetSampleRate(const MODTYPE type) const //------------------------------------------------------- { Modified: trunk/OpenMPT/soundlib/ModSample.h =================================================================== --- trunk/OpenMPT/soundlib/ModSample.h 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/ModSample.h 2012-05-14 21:50:12 UTC (rev 1269) @@ -13,21 +13,22 @@ // Sample Struct struct ModSample { - UINT nLength, nLoopStart, nLoopEnd; // In samples, not bytes - UINT nSustainStart, nSustainEnd; // Dito - LPSTR pSample; // Pointer to sample data - UINT nC5Speed; // Frequency of middle c, in Hz (for IT/S3M/MPTM) - WORD nPan; // Default sample panning (if pan flag is set) - WORD nVolume; // Default volume - WORD nGlobalVol; // Global volume (sample volume is multiplied by this) - WORD uFlags; // Sample flags - signed char RelativeTone; // Relative note to middle c (for MOD/XM) - signed char nFineTune; // Finetune period (for MOD/XM) - BYTE nVibType; // Auto vibrato type - BYTE nVibSweep; // Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full strength) - BYTE nVibDepth; // Auto vibrato depth - BYTE nVibRate; // Auto vibrato rate (speed) - //CHAR name[MAX_SAMPLENAME]; // Maybe it would be nicer to have sample names here, but that would require some refactoring. Also, would this slow down the mixer (cache misses)? + SmpLength nLength; // In samples, not bytes + SmpLength nLoopStart, nLoopEnd; // Dito + SmpLength nSustainStart, nSustainEnd; // Dito + LPSTR pSample; // Pointer to sample data + uint32 nC5Speed; // Frequency of middle c, in Hz (for IT/S3M/MPTM) + uint16 nPan; // Default sample panning (if pan flag is set) + uint16 nVolume; // Default volume + uint16 nGlobalVol; // Global volume (sample volume is multiplied by this) + uint16 uFlags; // Sample flags + int8 RelativeTone; // Relative note to middle c (for MOD/XM) + int8 nFineTune; // Finetune period (for MOD/XM) + uint8 nVibType; // Auto vibrato type + uint8 nVibSweep; // Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full strength) + uint8 nVibDepth; // Auto vibrato depth + uint8 nVibRate; // Auto vibrato rate (speed) + //CHAR name[MAX_SAMPLENAME]; // Maybe it would be nicer to have sample names here, but that would require some refactoring. Also, would this slow down the mixer (cache misses)? CHAR filename[MAX_SAMPLEFILENAME]; // Return the size of one (elementary) sample in bytes. @@ -48,4 +49,7 @@ // Translate sample properties between two given formats. void Convert(MODTYPE fromType, MODTYPE toType); + + // Initialize sample slot with default values. + void Initialize(MODTYPE type = MOD_TYPE_NONE); }; Modified: trunk/OpenMPT/soundlib/ModSequence.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/ModSequence.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -118,8 +118,10 @@ std::fill(iter, end(), GetInvalidPatIndex()); if(GetLengthTailTrimmed() > specs.ordersMax) { +#ifdef MODPLUG_TRACKER if (m_pSndFile->GetpModDoc()) m_pSndFile->GetpModDoc()->AddToLog("WARNING: Order list has been trimmed!\n"); +#endif // MODPLUG_TRACKER } } resize(specs.ordersMax); @@ -532,9 +534,11 @@ const ORDERINDEX nFirstOrder = GetLengthTailTrimmed() + 1; // +1 for separator item if(nFirstOrder + GetSequence(1).GetLengthTailTrimmed() > m_pSndFile->GetModSpecifications().ordersMax) { +#ifdef MODPLUG_TRACKER wsprintf(s, "WARNING: Cannot merge Sequence %d (too long!)\n", removedSequences); if (m_pSndFile->GetpModDoc()) m_pSndFile->GetpModDoc()->AddToLog(s); +#endif // MODPLUG_TRACKER RemoveSequence(1); continue; } @@ -569,9 +573,11 @@ } else { // cannot create new pattern: notify the user +#ifdef MODPLUG_TRACKER wsprintf(s, "CONFLICT: Pattern break commands in Pattern %d might be broken since it has been used in several sequences!", nPat); if (m_pSndFile->GetpModDoc()) m_pSndFile->GetpModDoc()->AddToLog(s); +#endif // MODPLUG_TRACKER } } m->param = static_cast<BYTE>(m->param + nFirstOrder); Modified: trunk/OpenMPT/soundlib/Snd_defs.h =================================================================== --- trunk/OpenMPT/soundlib/Snd_defs.h 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/Snd_defs.h 2012-05-14 21:50:12 UTC (rev 1269) @@ -46,11 +46,11 @@ -#define MOD_AMIGAC2 0x1AB // Period of Amiga middle-c -#define MAX_SAMPLE_LENGTH 0x10000000 // 0x04000000 (64MB -> now 256MB). - // Note: Sample size in bytes can be more than 256 MB. - // The meaning of this constant is handled differently in various places; sometimes it's samples, sometimes it's bytes... -#define MAX_SAMPLE_RATE 192000 // Max playback / render rate in Hz +#define MOD_AMIGAC2 0x1AB // Period of Amiga middle-c +const SmpLength MAX_SAMPLE_LENGTH = 0x10000000; // 0x04000000 (64MB -> now 256MB). + // Note: Sample size in bytes can be more than 256 MB. + // The meaning of this constant is handled differently in various places; sometimes it's samples, sometimes it's bytes... +#define MAX_SAMPLE_RATE 192000 // Max playback / render rate in Hz const ROWINDEX MAX_PATTERN_ROWS = 1024; // -> CODE#0008 -> DESC="#define to set pattern size" -! BEHAVIOUR_CHANGE#0008 const ORDERINDEX MAX_ORDERS = 256; @@ -352,7 +352,7 @@ // Misc Flags (can safely be turned on or off) #define SNDMIX_DIRECTTODISK 0x10000 // WAV writer mode #define SNDMIX_ENABLEMMX 0x20000 // use MMX-accelerated code -#define SNDMIX_NOBACKWARDJUMPS 0x40000 // stop when jumping back in the order (currently unused as it seems) +//#define SNDMIX_NOBACKWARDJUMPS 0x40000 // stop when jumping back in the order (currently unused as it seems) #define SNDMIX_MAXDEFAULTPAN 0x80000 // Used by the MOD loader (currently unused) #define SNDMIX_MUTECHNMODE 0x100000 // Notes are not played on muted channels Modified: trunk/OpenMPT/soundlib/XMTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/XMTools.cpp 2012-05-13 20:04:12 UTC (rev 1268) +++ trunk/OpenMPT/soundlib/XMTools.cpp 2012-05-14 21:50:12 UTC (rev 1269) @@ -387,17 +387,17 @@ void XMSample::ConvertToMPT(ModSample &mptSmp) const //-------------------------------------------------- { + mptSmp.Initialize(MOD_TYPE_XM); + // Volume mptSmp.nVolume = vol * 4; LimitMax(mptSmp.nVolume, WORD(256)); - mptSmp.nGlobalVol = 64; // Panning mptSmp.nPan = pan; mptSmp.uFlags = CHN_PANNING; // Sample Frequency - mptSmp.nC5Speed = 0; mptSmp.nFineTune = finetune; mptSmp.RelativeTone = relnote; @@ -405,7 +405,6 @@ mptSmp.nLength = LittleEndian(length); mptSmp.nLoopStart = LittleEndian(loopStart); mptSmp.nLoopEnd = mptSmp.nLoopStart + LittleEndian(loopLength); - mptSmp.nSustainStart = mptSmp.nSustainEnd = 0; if((flags & XMSample::sample16Bit)) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-14 22:23:52
|
Revision: 1270 http://modplug.svn.sourceforge.net/modplug/?rev=1270&view=rev Author: saga-games Date: 2012-05-14 22:23:45 +0000 (Mon, 14 May 2012) Log Message: ----------- [Imp] Rewrote AIFF reader using the new ChunkReader class (which will be used for more loaders including J2B, PSM, WAV in the near future). Added support for AIFF loop points and little-endian sample data. Note: 24-Bit and 32-Bit Big-Endian PCM and 32-Bit floating point are not imported correctly. Modified Paths: -------------- trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/Loaders.h trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/Sndfile.h Added Paths: ----------- trunk/OpenMPT/soundlib/ChunkReader.h Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-05-14 21:50:12 UTC (rev 1269) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-05-14 22:23:45 UTC (rev 1270) @@ -334,6 +334,7 @@ <ClInclude Include="..\common\Reporting.h" /> <ClInclude Include="..\common\StringFixer.h" /> <ClInclude Include="..\common\typedefs.h" /> + <ClInclude Include="..\soundlib\ChunkReader.h" /> <ClInclude Include="..\soundlib\ITTools.h" /> <ClInclude Include="..\soundlib\MIDIEvents.h" /> <ClInclude Include="..\soundlib\MIDIMacros.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-05-14 21:50:12 UTC (rev 1269) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-05-14 22:23:45 UTC (rev 1270) @@ -816,6 +816,9 @@ <ClInclude Include="..\soundlib\MIDIEvents.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\soundlib\ChunkReader.h"> + <Filter>Module Loaders</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Added: trunk/OpenMPT/soundlib/ChunkReader.h =================================================================== --- trunk/OpenMPT/soundlib/ChunkReader.h (rev 0) +++ trunk/OpenMPT/soundlib/ChunkReader.h 2012-05-14 22:23:45 UTC (rev 1270) @@ -0,0 +1,125 @@ +/* + * ChunkReader.h + * ------------- + * Purpose: An extended FileReader to read Iff-like chunk-based file structures. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "Loaders.h" +#include <vector> + + +//=================================== +class ChunkReader : public FileReader +//=================================== +{ +public: + + ChunkReader(const char *data, size_t length) : FileReader(data, length) { } + ChunkReader(const FileReader &other) : FileReader(other) { } + + template<typename T> + //================= + class ChunkListItem + //================= + { + private: + const T chunkHeader; + ChunkReader chunkData; + + public: + ChunkListItem(const T &header, const FileReader &data) : chunkHeader(header), chunkData(data) { } + const T &GetHeader() const { return chunkHeader; } + FileReader &GetData() { return chunkData; } + + bool operator== (const ChunkListItem<T> &other) + { + return (GetHeader().GetID() == other.GetHeader().GetID()); + } + }; + + template<typename T> + //===================================================== + class ChunkList : public std::vector<ChunkListItem<T> > + //===================================================== + { + public: + + // Check if the list contains a given chunk. + template<typename IdType> + bool ChunkExists(IdType id) const + { + for(const_iterator iter = begin(); iter != end(); iter++) + { + if(iter->GetHeader().GetID() == id) + { + return true; + } + } + return false; + } + + // Retrieve the first chunk with a given ID. + template<typename IdType> + FileReader GetChunk(IdType id) + { + for(iterator iter = begin(); iter != end(); iter++) + { + if(iter->GetHeader().GetID() == id) + { + return iter->GetData(); + } + } + return FileReader(nullptr, 0); + } + + // Retrieve all chunks with a given ID. + template<typename IdType> + std::vector<FileReader> GetAllChunks(IdType id) + { + std::vector<FileReader> result; + for(iterator iter = begin(); iter != end(); iter++) + { + if(iter->GetHeader().GetID() == id) + { + result.push_back(iter->GetData()); + } + } + return result; + } + + }; + + + // Read a series of "T" chunks until the end of file is reached. + template<typename T> + ChunkList<T> ReadChunks(size_t padding) + { + ChunkList<T> result; + while(BytesLeft()) + { + T chunkHeader; + if(!Read(chunkHeader)) + { + break; + } + + size_t dataSize = chunkHeader.GetLength(); + ChunkListItem<T> resultItem(chunkHeader, GetChunk(dataSize)); + result.push_back(resultItem); + + // Skip padding bytes + if(padding != 0 && dataSize % padding != 0) + { + Skip(padding - (dataSize % padding)); + } + } + + return result; + } +}; Modified: trunk/OpenMPT/soundlib/Loaders.h =================================================================== --- trunk/OpenMPT/soundlib/Loaders.h 2012-05-14 21:50:12 UTC (rev 1269) +++ trunk/OpenMPT/soundlib/Loaders.h 2012-05-14 22:23:45 UTC (rev 1270) @@ -33,6 +33,7 @@ public: FileReader(const char *data, size_t length) : streamData(data), streamLength(length), streamPos(0) { } + FileReader(const FileReader &other) : streamData(other.streamData), streamLength(other.streamLength), streamPos(other.streamPos) { } // Returns true if the object points to a valid stream. bool IsValid() const Modified: trunk/OpenMPT/soundlib/Sampleio.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sampleio.cpp 2012-05-14 21:50:12 UTC (rev 1269) +++ trunk/OpenMPT/soundlib/Sampleio.cpp 2012-05-14 22:23:45 UTC (rev 1270) @@ -22,21 +22,25 @@ #include "../common/StringFixer.h" #include "../common/Reporting.h" #include "../mptrack/version.h" +#include "ChunkReader.h" #pragma warning(disable:4244) bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength) //-------------------------------------------------------------------------------------------------- { - if ((!nSample) || (nSample >= MAX_SAMPLES)) return false; - if ((!ReadWAVSample(nSample, lpMemFile, dwFileLength)) - && (!ReadXISample(nSample, lpMemFile, dwFileLength)) - && (!ReadAIFFSample(nSample, lpMemFile, dwFileLength)) - && (!ReadITSSample(nSample, lpMemFile, dwFileLength)) - && (!ReadPATSample(nSample, lpMemFile, dwFileLength)) - && (!Read8SVXSample(nSample, lpMemFile, dwFileLength)) - && (!ReadS3ISample(nSample, lpMemFile, dwFileLength))) + FileReader file(reinterpret_cast<const char *>(lpMemFile), dwFileLength); + if(!nSample || nSample >= MAX_SAMPLES) return false; + if(!ReadWAVSample(nSample, lpMemFile, dwFileLength) + && !ReadXISample(nSample, lpMemFile, dwFileLength) + && !ReadAIFFSample(nSample, file) + && !ReadITSSample(nSample, lpMemFile, dwFileLength) + && !ReadPATSample(nSample, lpMemFile, dwFileLength) + && !Read8SVXSample(nSample, lpMemFile, dwFileLength) + && !ReadS3ISample(nSample, lpMemFile, dwFileLength)) + { return false; + } return true; } @@ -1392,122 +1396,361 @@ ///////////////////////////////////////////////////////////////////////////////////////// // AIFF File I/O -typedef struct AIFFFILEHEADER + +#pragma pack(push, 1) + +// AIFF header +struct AIFFHeader { - DWORD dwFORM; // "FORM" -> 0x4D524F46 - DWORD dwLen; - DWORD dwAIFF; // "AIFF" -> 0x46464941 -} AIFFFILEHEADER; + // 32-Bit chunk identifiers + enum AIFFMagic + { + idFORM = 0x464F524D, + idAIFF = 0x41494646, + idAIFC = 0x41494643, + }; -typedef struct AIFFCOMM + uint32 magic; // FORM + uint32 length; // Size of the file, not including magic an length + uint32 type; // AIFF or AIFC + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesBE(magic); + SwapBytesBE(type); + } +}; + + +// General IFF Chunk header +struct AIFFChunk { - DWORD dwCOMM; // "COMM" -> 0x4D4D4F43 - DWORD dwLen; - WORD wChannels; - WORD wFramesHi; // Align! - WORD wFramesLo; - WORD wSampleSize; - BYTE xSampleRate[10]; -} AIFFCOMM; + // 32-Bit chunk identifiers + enum ChunkIdentifiers + { + idCOMM = 0x434F4D4D, + idSSND = 0x53534E44, + idINST = 0x494E5354, + idMARK = 0x4D41524B, + idNAME = 0x4E414D45, + }; -typedef struct AIFFSSND + uint32 id; // See ChunkIdentifiers + uint32 length; // Chunk size without header + + size_t GetLength() const + { + uint32 l = length; + return SwapBytesBE(l); + } + + ChunkIdentifiers GetID() const + { + uint32 i = id; + return static_cast<ChunkIdentifiers>(SwapBytesBE(i)); + } +}; + + +// "Common" chunk (in AIFC, a compression ID and compression name follows this header, but apart from that it's identical) +struct AIFFCommonChunk { - DWORD dwSSND; // "SSND" -> 0x444E5353 - DWORD dwLen; - DWORD dwOffset; - DWORD dwBlkSize; -} AIFFSSND; + uint16 numChannels; + uint32 numSampleFrames; + uint16 sampleSize; + uint8 sampleRate[10]; // Sample rate in 80-Bit floating point + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesBE(numChannels); + SwapBytesBE(numSampleFrames); + SwapBytesBE(sampleSize); + } -static DWORD FetchLong(LPBYTE p) + // Convert sample rate to integer + uint32 GetSampleRate() const + { + uint32 mantissa, last = 0; + uint8 exp; + + mantissa = SwapBytesBE(static_cast<uint32 >(*reinterpret_cast<const uint32 *>(sampleRate + 2))); + exp = 30 - sampleRate[1]; + while(exp--) + { + last = mantissa; + mantissa >>= 1; + } + if(last & 1) mantissa++; + return mantissa; + } +}; + + +// Sound chunk +struct AIFFSoundChunk { - DWORD d = p[0]; - d = (d << 8) | p[1]; - d = (d << 8) | p[2]; - d = (d << 8) | p[3]; - return d; -} + uint32 offset; + uint32 blockSize; + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesBE(offset); + SwapBytesBE(blockSize); + } +}; -static DWORD Ext2Long(LPBYTE p) + +// Marker +struct AIFFMarker { - DWORD mantissa, last=0; - BYTE exp; + uint16 id; + uint32 position; // Position in sample + uint8 nameLength; // Not counting eventually existing padding byte in name string - mantissa = FetchLong(p+2); - exp = 30 - p[1]; - while (exp--) + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() { - last = mantissa; - mantissa >>= 1; + SwapBytesBE(id); + SwapBytesBE(position); + }}; + + +// Instrument loop +struct AIFFInstrumentLoop +{ + enum PlayModes + { + noLoop = 0, + loopNormal = 1, + loopBidi = 2, + }; + + uint16 playMode; + uint16 beginLoop; // Marker index + uint16 endLoop; // Marker index + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesBE(playMode); + SwapBytesBE(beginLoop); + SwapBytesBE(endLoop); } - if (last & 1) mantissa++; - return mantissa; -} +}; +struct AIFFInstrumentChunk +{ + uint8 baseNote; + uint8 detune; + uint8 lowNote; + uint8 highNote; + uint8 lowVelocity; + uint8 highVelocity; + uint16 gain; + AIFFInstrumentLoop sustainLoop; + AIFFInstrumentLoop releaseLoop; -bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, LPBYTE lpMemFile, DWORD dwFileLength) -//---------------------------------------------------------------------------------------- + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + sustainLoop.ConvertEndianness(); + releaseLoop.ConvertEndianness(); + } +}; + +#pragma pack(pop) + + +bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader file) +//------------------------------------------------------------------- { - DWORD dwMemPos = sizeof(AIFFFILEHEADER); - DWORD dwFORMLen, dwCOMMLen, dwSSNDLen; - AIFFFILEHEADER *phdr = (AIFFFILEHEADER *)lpMemFile; - AIFFCOMM *pcomm; - AIFFSSND *psnd; - UINT nType; + ChunkReader chunkFile(file); - if ((!lpMemFile) || (dwFileLength < (DWORD)sizeof(AIFFFILEHEADER))) return false; - dwFORMLen = BigEndian(phdr->dwLen); - if ((phdr->dwFORM != 0x4D524F46) || (phdr->dwAIFF != 0x46464941) - || (dwFORMLen > dwFileLength) || (dwFORMLen < (DWORD)sizeof(AIFFCOMM))) return false; - pcomm = (AIFFCOMM *)(lpMemFile+dwMemPos); - dwCOMMLen = BigEndian(pcomm->dwLen); - if ((pcomm->dwCOMM != 0x4D4D4F43) || (dwCOMMLen < 0x12) || (dwCOMMLen >= dwFileLength)) return false; - if ((pcomm->wChannels != 0x0100) && (pcomm->wChannels != 0x0200)) return false; - if ((pcomm->wSampleSize != 0x0800) && (pcomm->wSampleSize != 0x1000)) return false; - dwMemPos += dwCOMMLen + 8; - if (dwMemPos + sizeof(AIFFSSND) >= dwFileLength) return false; - psnd = (AIFFSSND *)(lpMemFile+dwMemPos); - dwSSNDLen = BigEndian(psnd->dwLen); - if ((psnd->dwSSND != 0x444E5353) || (dwSSNDLen >= dwFileLength) || (dwSSNDLen < 8)) return false; - dwMemPos += sizeof(AIFFSSND); - if (dwMemPos >= dwFileLength) return false; - DestroySample(nSample); - if (pcomm->wChannels == 0x0100) + // Verify header + AIFFHeader fileHeader; + if(!chunkFile.ReadConvertEndianness(fileHeader) + || fileHeader.magic != AIFFHeader::idFORM + || (fileHeader.type != AIFFHeader::idAIFF && fileHeader.type != AIFFHeader::idAIFC)) { - nType = (pcomm->wSampleSize == 0x1000) ? RS_PCM16M : RS_PCM8S; + return false; + } + + ChunkReader::ChunkList<AIFFChunk> chunks = chunkFile.ReadChunks<AIFFChunk>(2); + + // Read COMM chunk + FileReader commChunk(chunks.GetChunk(AIFFChunk::idCOMM)); + AIFFCommonChunk sampleInfo; + if(!commChunk.IsValid() + || !commChunk.ReadConvertEndianness(sampleInfo)) + { + return false; + } + + // Is this a proper sample? + if(sampleInfo.numSampleFrames == 0 + || sampleInfo.numChannels < 1 || sampleInfo.numChannels > 2 + || sampleInfo.sampleSize < 1 || sampleInfo.sampleSize > 32) + { + return false; + } + + // Read compression type in AIFF-C files. + char compression[4] = { 'N', 'O', 'N', 'E' }; + bool littleEndian = false; + if(fileHeader.type == AIFFHeader::idAIFC) + { + if(!commChunk.ReadArray(compression)) + { + return false; + } + littleEndian = !memcmp(compression, "twos", 4); + } + + // Read SSND chunk + FileReader soundChunk(chunks.GetChunk(AIFFChunk::idSSND)); + AIFFSoundChunk sampleHeader; + if(!soundChunk.IsValid() + || !soundChunk.ReadConvertEndianness(sampleHeader) + || soundChunk.BytesLeft() <= sampleHeader.offset) + { + return false; + } + + UINT format, wavFormat = 1; + if(sampleInfo.numChannels == 1) + { + if(sampleInfo.sampleSize <= 8) + { + format = RS_PCM8S; + } else if(sampleInfo.sampleSize <= 16) + { + format = littleEndian ? RS_PCM16S : RS_PCM16M; + } else if(sampleInfo.sampleSize <= 24) + { + format = littleEndian ? RS_PCM24S : RS_PCM24S; // FIXME: No big-endian support! + } else if(sampleInfo.sampleSize <= 32) + { + format = littleEndian ? RS_PCM32S : RS_PCM32S; // FIXME: No big-endian support! + } else + { + return false; + } } else { - nType = (pcomm->wSampleSize == 0x1000) ? RS_STIPCM16M : RS_STIPCM8S; + if(sampleInfo.sampleSize <= 8) + { + format = RS_STIPCM8S; + } else if(sampleInfo.sampleSize <= 16) + { + format = littleEndian ? RS_STIPCM16S : RS_STIPCM16M; + } else if(sampleInfo.sampleSize <= 24) + { + format = littleEndian ? RS_STIPCM24S : RS_STIPCM24S; // FIXME: No big-endian support! + } else if(sampleInfo.sampleSize <= 32) + { + format = littleEndian ? RS_STIPCM32S : RS_STIPCM32S; // FIXME: No big-endian support! + } else + { + return false; + } } - UINT samplesize = (pcomm->wSampleSize >> 11) * (pcomm->wChannels >> 8); - if (!samplesize) samplesize = 1; - ModSample *pSmp = &Samples[nSample]; - if (pSmp->pSample) + if(!memcmp(compression, "fl32", 4) || !memcmp(compression, "FL32", 4)) { - FreeSample(pSmp->pSample); - pSmp->pSample = nullptr; - pSmp->nLength = 0; + // FIXME: No big-endian support! + wavFormat = 3; } - pSmp->nLength = dwSSNDLen / samplesize; - pSmp->nLoopStart = pSmp->nLoopEnd = 0; - pSmp->nSustainStart = pSmp->nSustainEnd = 0; - pSmp->nC5Speed = Ext2Long(pcomm->xSampleRate); - pSmp->nPan = 128; - pSmp->nVolume = 256; - pSmp->nGlobalVol = 64; - pSmp->uFlags = (pcomm->wSampleSize > 0x0800) ? CHN_16BIT : 0; - if (pcomm->wChannels >= 0x0200) pSmp->uFlags |= CHN_STEREO; - if (GetType() & MOD_TYPE_XM) pSmp->uFlags |= CHN_PANNING; - pSmp->RelativeTone = 0; - pSmp->nFineTune = 0; - if (GetType() & MOD_TYPE_XM) FrequencyToTranspose(pSmp); - pSmp->nVibType = pSmp->nVibSweep = pSmp->nVibDepth = pSmp->nVibRate = 0; - pSmp->filename[0] = 0; - m_szNames[nSample][0] = 0; - if (pSmp->nLength > MAX_SAMPLE_LENGTH) pSmp->nLength = MAX_SAMPLE_LENGTH; - ReadSample(pSmp, nType, (LPSTR)(lpMemFile+dwMemPos), dwFileLength-dwMemPos); + + soundChunk.Skip(sampleHeader.offset); + + ModSample &mptSample = Samples[nSample]; + DestroySample(nSample); + mptSample.Initialize(); + mptSample.nLength = sampleInfo.numSampleFrames; + mptSample.nC5Speed = sampleInfo.GetSampleRate(); + LimitMax(mptSample.nLength, MAX_SAMPLE_LENGTH); + + ReadSample(&mptSample, format, soundChunk, wavFormat); + + // Read MARK and INST chunk to extract sample loops + FileReader markerChunk(chunks.GetChunk(AIFFChunk::idMARK)); + FileReader instChunk(chunks.GetChunk(AIFFChunk::idINST)); + AIFFInstrumentChunk instrHeader; + if(markerChunk.IsValid() && instChunk.IsValid() && instChunk.ReadConvertEndianness(instrHeader)) + { + size_t numMarkers = markerChunk.ReadUint16BE(); + + vector<AIFFMarker> markers; + for(size_t i = 0; i < numMarkers; i++) + { + AIFFMarker marker; + if(!markerChunk.ReadConvertEndianness(marker)) + { + break; + } + markers.push_back(marker); + markerChunk.Skip(marker.nameLength + ((marker.nameLength % 2) == 0 ? 1 : 0)); + } + + if(instrHeader.sustainLoop.playMode != AIFFInstrumentLoop::noLoop) + { + mptSample.uFlags |= CHN_SUSTAINLOOP | (instrHeader.sustainLoop.playMode == AIFFInstrumentLoop::loopBidi ? CHN_PINGPONGSUSTAIN : 0); + } + + if(instrHeader.releaseLoop.playMode != AIFFInstrumentLoop::noLoop) + { + mptSample.uFlags |= CHN_LOOP | (instrHeader.releaseLoop.playMode == AIFFInstrumentLoop::loopBidi ? CHN_PINGPONGLOOP : 0); + } + + // Read markers + for(vector<AIFFMarker>::iterator iter = markers.begin(); iter != markers.end(); iter++) + { + if(iter->id == instrHeader.sustainLoop.beginLoop) + { + mptSample.nSustainStart = iter->position; + } + if(iter->id == instrHeader.sustainLoop.endLoop) + { + mptSample.nSustainEnd = iter->position; + } + if(iter->id == instrHeader.releaseLoop.beginLoop) + { + mptSample.nLoopStart = iter->position; + } + if(iter->id == instrHeader.releaseLoop.endLoop) + { + mptSample.nLoopEnd = iter->position; + } + } + // Sanitize loops + LimitMax(mptSample.nSustainEnd, mptSample.nLength); + LimitMax(mptSample.nLoopEnd, mptSample.nLength); + if(mptSample.nSustainStart >= mptSample.nSustainEnd) + { + mptSample.nSustainStart = mptSample.nSustainEnd = 0; + mptSample.uFlags &= ~CHN_SUSTAINLOOP; + } + if(mptSample.nLoopStart >= mptSample.nLoopEnd) + { + mptSample.nLoopStart = mptSample.nLoopEnd = 0; + mptSample.uFlags &= ~CHN_LOOP; + } + } + + // Extract sample name + FileReader nameChunk(chunks.GetChunk(AIFFChunk::idNAME)); + if(nameChunk.IsValid()) + { + nameChunk.ReadString<StringFixer::spacePadded>(m_szNames[nSample], nameChunk.GetLength()); + } else + { + strcpy(m_szNames[nSample], ""); + } + + mptSample.Convert(MOD_TYPE_IT, GetType()); return true; } @@ -1821,7 +2064,7 @@ repeatHiSamples, /* # samples in the high octave repeat part */ samplesPerHiCycle; /* # samples/cycle in high octave, else 0 */ WORD samplesPerSec; /* data sampling rate */ - BYTE ctOctave, /* # octaves of waveforms */ + BYTE ctOctave, /* # octaves of waveforms */ sCompression; /* data compression technique used */ DWORD Volume; } IFFVHDR; Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-05-14 21:50:12 UTC (rev 1269) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-05-14 22:23:45 UTC (rev 1270) @@ -626,7 +626,7 @@ bool ReadWAVSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength, DWORD *pdwWSMPOffset=NULL); bool ReadPATSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); bool ReadS3ISample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); - bool ReadAIFFSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); + bool ReadAIFFSample(SAMPLEINDEX nSample, FileReader file); bool ReadXISample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); UINT ReadITSSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength, DWORD dwOffset=0); bool Read8SVXSample(UINT nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-20 16:39:35
|
Revision: 1276 http://modplug.svn.sourceforge.net/modplug/?rev=1276&view=rev Author: saga-games Date: 2012-05-20 16:39:28 +0000 (Sun, 20 May 2012) Log Message: ----------- [Fix] ChunkReader class apparently didn't compile on VC2008. Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/soundlib/ChunkReader.h Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2012-05-19 19:44:58 UTC (rev 1275) +++ trunk/OpenMPT/common/misc_util.h 2012-05-20 16:39:28 UTC (rev 1276) @@ -63,14 +63,14 @@ // Copy given object to other location. template <class T> -inline void MemCopy(T &destination, const T &source) -//-------------------------------------------------- +inline T &MemCopy(T &destination, const T &source) +//------------------------------------------------ { #if _HAS_TR1 static_assert(std::tr1::is_pointer<T>::value == false, "Won't copy pointers."); static_assert(std::tr1::is_pod<T>::value == true, "Won't copy non-pods."); #endif - memcpy(&destination, &source, sizeof(T)); + return *static_cast<T *>(memcpy(&destination, &source, sizeof(T))); } Modified: trunk/OpenMPT/soundlib/ChunkReader.h =================================================================== --- trunk/OpenMPT/soundlib/ChunkReader.h 2012-05-19 19:44:58 UTC (rev 1275) +++ trunk/OpenMPT/soundlib/ChunkReader.h 2012-05-20 16:39:28 UTC (rev 1276) @@ -34,6 +34,12 @@ public: ChunkListItem(const T &header, const FileReader &data) : chunkHeader(header), chunkData(data) { } + // VC2008 needs operator=, VC2010 doesn't... + ChunkListItem<T>& operator= (const ChunkListItem<T> &other) + { + return MemCopy(*this, other); + } + const T &GetHeader() const { return chunkHeader; } FileReader &GetData() { return chunkData; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-23 14:59:08
|
Revision: 1278 http://modplug.svn.sourceforge.net/modplug/?rev=1278&view=rev Author: saga-games Date: 2012-05-23 14:58:53 +0000 (Wed, 23 May 2012) Log Message: ----------- [Ref] Mega Refactoring: Total rewrite of sample loading code. Everything regarding sample loading can now be found in SampleIO.h, SampleIO.cpp and SampleFormatConverters.h (original content of SampleIO.cpp has been moved to SampleFormats.cpp). Template functions and functors are used to avoid duplicate code (and still create nice small assembly when compiler is optimizing). Some advantages: - Much easier handling of sample loading through the SampleIO class. - Support for big-endian samples > 16-Bit for example in AIFF files - Support for obscure flags in IT files and IT samples (for example delta-encoded samples). - Less pollution of CSoundFile. Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/mptrack/Ctrl_pat.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/Ctrl_smp.h trunk/OpenMPT/mptrack/InputHandler.cpp trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/SampleEditorDialogs.h trunk/OpenMPT/mptrack/Undo.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Dlsbank.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_mo3.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_wav.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Loaders.h trunk/OpenMPT/soundlib/Message.cpp trunk/OpenMPT/soundlib/ModInstrument.h trunk/OpenMPT/soundlib/ModSample.cpp trunk/OpenMPT/soundlib/ModSample.h trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/XMTools.cpp trunk/OpenMPT/soundlib/XMTools.h trunk/OpenMPT/soundlib/load_j2b.cpp trunk/OpenMPT/soundlib/mod_specifications.h trunk/OpenMPT/soundlib/modcommand.cpp trunk/OpenMPT/soundlib/modsmp_ctrl.cpp Added Paths: ----------- trunk/OpenMPT/soundlib/SampleFormatConverters.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/SampleIO.h Removed Paths: ------------- trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/wavConverter.h Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/common/misc_util.h 2012-05-23 14:58:53 UTC (rev 1278) @@ -281,6 +281,9 @@ // Like std::min, but avoids conflict with min-macro. template <class T> inline const T& Min(const T& a, const T& b) {return (std::min)(a, b);} + // Minimum of 3 values + template <class T> inline const T& Min(const T& a, const T& b, const T& c) {return Min(Min(a, b), c);} + // Returns maximum value of given integer type. template <class T> inline T MaxValueOfType(const T&) {static_assert(std::numeric_limits<T>::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits<T>::max)();} Modified: trunk/OpenMPT/mptrack/Ctrl_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -909,7 +909,7 @@ m_OrderList.InvalidateRect(NULL, FALSE); m_OrderList.SetCurSel(nInsertWhere); - // If the first duplicated order is f.e. a +++ item, we need to move the pattern display on or else we'll still edit the previously shown pattern. + // If the first duplicated order is e.g. a +++ item, we need to move the pattern display on or else we'll still edit the previously shown pattern. ORDERINDEX showPattern = min(nInsertWhere, pSndFile->Order.GetLastIndex()); while(!pSndFile->Patterns.IsValidPat(pSndFile->Order[showPattern]) && showPattern < pSndFile->Order.GetLastIndex()) { Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -778,34 +778,35 @@ EndWaitCursor(); if ((m_nPreviousRawFormat != 0) || (dlg.DoModal() == IDOK)) { + m_nPreviousRawFormat = (dlg.GetRemeberFormat() ? dlg.GetSampleFormat() : 0); - m_nPreviousRawFormat = ((dlg.GetRemeberFormat())) ? dlg.GetSampleFormat() : 0; - BeginWaitCursor(); - UINT flags = 0; ModSample &sample = m_pSndFile->GetSample(m_nSample); CriticalSection cs; m_pSndFile->DestroySample(m_nSample); sample.nLength = len; - sample.uFlags = RS_PCM8S; - if (dlg.GetSampleFormat() & ER_16BIT) + SampleIO sampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + (dlg.GetSampleFormat() & ER_UNSIGNED) ? SampleIO::unsignedPCM : SampleIO::signedPCM); + + if(dlg.GetSampleFormat() & ER_16BIT) { - sample.nLength >>= 1; - flags = RS_PCM16S; + sample.nLength /= 2; + sampleIO |= SampleIO::_16bit; } - if (dlg.GetSampleFormat() & ER_UNSIGNED) - { - flags++; - } + // Interleaved Stereo Sample - if (dlg.GetSampleFormat() & ER_STEREO) + if(dlg.GetSampleFormat() & ER_STEREO) { - sample.nLength >>= 1; - flags |= 0x40|RSF_STEREO; + sample.nLength /= 2; + sampleIO |= SampleIO::stereoInterleaved; } + LPSTR p16 = (LPSTR)lpFile; DWORD l16 = len; if ((sample.uFlags & CHN_16BIT) && (len & 1)) @@ -813,7 +814,8 @@ p16++; l16--; } - if (m_pSndFile->ReadSample(&sample, flags, p16, l16)) + + if (sampleIO.ReadSample(sample, p16, l16)) { bOk = true; @@ -875,8 +877,8 @@ } -bool CCtrlSamples::OpenSample(CSoundFile *pSndFile, SAMPLEINDEX nSample) -//---------------------------------------------------------------------- +bool CCtrlSamples::OpenSample(const CSoundFile *pSndFile, SAMPLEINDEX nSample) +//---------------------------------------------------------------------------- { if ((!pSndFile) || (!nSample) || (nSample > pSndFile->m_nSamples)) return false; @@ -962,17 +964,7 @@ if(bDuplicate && nOldSmp >= 1 && nOldSmp <= pSndFile->GetNumSamples()) { m_pModDoc->GetSampleUndo().PrepareUndo(smp, sundo_replace); - MemCopy(m_pSndFile->GetSample(smp), m_pSndFile->GetSample(nOldSmp)); - strcpy(m_pSndFile->m_szNames[smp], m_pSndFile->m_szNames[nOldSmp]); - // Clone sample. - if(m_pSndFile->GetSample(nOldSmp).pSample != nullptr) - { - if((m_pSndFile->GetSample(smp).pSample = CSoundFile::AllocateSample(m_pSndFile->GetSample(nOldSmp).GetSampleSizeInBytes())) != nullptr) - { - memcpy(m_pSndFile->GetSample(smp).pSample, m_pSndFile->GetSample(nOldSmp).pSample, m_pSndFile->GetSample(nOldSmp).GetSampleSizeInBytes()); - } - m_pSndFile->AdjustSampleLoop(&m_pSndFile->GetSample(smp)); - } + pSndFile->ReadSampleFromSong(smp, pSndFile, nOldSmp); } m_pModDoc->UpdateAllViews(NULL, (smp << HINT_SHIFT_SMP) | HINT_SAMPLEINFO | HINT_SAMPLEDATA | HINT_SMPNAMES); @@ -1045,10 +1037,10 @@ } if (m_pSndFile->GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT)) { - strncpy(szFileName, m_pSndFile->GetSample(m_nSample).filename, min(CountOf(m_pSndFile->GetSample(m_nSample).filename), CountOf(szFileName) - 1)); + strncpy(szFileName, m_pSndFile->GetSample(m_nSample).filename, Util::Min(CountOf(m_pSndFile->GetSample(m_nSample).filename), CountOf(szFileName) - 1)); } else { - strncpy(szFileName, m_pSndFile->m_szNames[m_nSample], min(CountOf(m_pSndFile->m_szNames[m_nSample]), CountOf(szFileName) - 1)); + strncpy(szFileName, m_pSndFile->m_szNames[m_nSample], Util::Min(CountOf(m_pSndFile->m_szNames[m_nSample]), CountOf(szFileName) - 1)); } if (!szFileName[0]) strcpy(szFileName, "untitled"); } @@ -1545,33 +1537,16 @@ if (sample.nSustainEnd >= dwEnd) sample.nSustainEnd += (dwEnd-dwStart); else if (sample.nSustainEnd > dwStart) sample.nSustainEnd += (sample.nSustainEnd - dwStart); - CriticalSection cs; - - for (UINT iFix=0; iFix<MAX_CHANNELS; iFix++) + ctrlSmp::ReplaceSample(sample, (LPSTR)pNewSample, dwNewLen, m_pSndFile); + if(!selection.selectionActive) { - if ((PVOID)m_pSndFile->Chn[iFix].pSample == pOriginal) + if(!(m_pSndFile->GetType() & MOD_TYPE_MOD)) { - m_pSndFile->Chn[iFix].pSample = (LPSTR)pNewSample; - m_pSndFile->Chn[iFix].pCurrentSample = (LPSTR)pNewSample; - m_pSndFile->Chn[iFix].dwFlags |= CHN_16BIT; + if(sample.nC5Speed < 1000000) sample.nC5Speed *= 2; + if(sample.RelativeTone < 84) sample.RelativeTone += 12; } } - if (selection.selectionActive == false) - { - if(!(m_pSndFile->m_nType & MOD_TYPE_MOD)) - { - if (sample.nC5Speed < 200000) sample.nC5Speed *= 2; - if (sample.RelativeTone < 84) sample.RelativeTone += 12; - } - } - sample.uFlags |= CHN_16BIT; - sample.pSample = (LPSTR)pNewSample; - sample.nLength = dwNewLen; - CSoundFile::FreeSample(pOriginal); - - cs.Leave(); - m_pModDoc->AdjustEndOfSample(m_nSample); if (selection.selectionActive == true) { @@ -1678,31 +1653,16 @@ if (sample.nSustainEnd > dwStart) sample.nSustainEnd -= (sample.nSustainEnd - dwStart)/2; if (sample.nSustainEnd > dwNewLen) sample.nSustainEnd = dwNewLen; - CriticalSection cs; - - for (UINT iFix=0; iFix<MAX_CHANNELS; iFix++) + ctrlSmp::ReplaceSample(sample, (LPSTR)pNewSample, dwNewLen, m_pSndFile); + if(!selection.selectionActive) { - if ((PVOID)m_pSndFile->Chn[iFix].pSample == pOriginal) + if(!(m_pSndFile->GetType() & MOD_TYPE_MOD)) { - m_pSndFile->Chn[iFix].pSample = (LPSTR)pNewSample; - m_pSndFile->Chn[iFix].pCurrentSample = NULL; - m_pSndFile->Chn[iFix].nLength = 0; + if(sample.nC5Speed > 2000) sample.nC5Speed /= 2; + if(sample.RelativeTone > -84) sample.RelativeTone -= 12; } } - if (selection.selectionActive == false) - { - if(!(m_pSndFile->m_nType & MOD_TYPE_MOD)) - { - if (sample.nC5Speed > 2000) sample.nC5Speed /= 2; - if (sample.RelativeTone > -84) sample.RelativeTone -= 12; - } - } - sample.nLength = dwNewLen; - sample.pSample = (LPSTR)pNewSample; - CSoundFile::FreeSample(pOriginal); - cs.Leave(); - m_pModDoc->AdjustEndOfSample(m_nSample); if (selection.selectionActive == true) { @@ -1926,15 +1886,21 @@ // Allocate new sample. Returned sample may not be exactly the size what ratio would suggest // so allocate a bit more(1.03*). - const DWORD nNewSampleLength = (DWORD)(1.03 * ratio * (double)sample.nLength); + const SmpLength nNewSampleLength = static_cast<SmpLength>(1.03 * ratio * (double)sample.nLength); //const DWORD nNewSampleLength = (DWORD)(0.5 + ratio * (double)sample.nLength); - PVOID pNewSample = CSoundFile::AllocateSample(nNewSampleLength * nChn * smpsize); - if(pNewSample == NULL) + void *pNewSample = nullptr; + if(nNewSampleLength <= MAX_SAMPLE_LENGTH) + { + pNewSample = CSoundFile::AllocateSample(nNewSampleLength * nChn * smpsize); + } + if(pNewSample == nullptr) + { return 3; + } // Save process button text (to be used as "progress bar" indicator while processing) CHAR oldText[255]; - GetDlgItemText(IDC_BUTTON1, oldText, 255); + GetDlgItemText(IDC_BUTTON1, oldText, CountOf(oldText)); // Get process button device context & client rect RECT progressBarRECT, processButtonRect; @@ -1978,7 +1944,7 @@ len = m_nStretchProcessStepLength; // Set settings to soundtouch. Zero value means 'use default', and - // setting value is read back after setting because not all settings are accepted. + // setting value is read back after setting because not all settings are accepted. if(m_nSequenceMs == 0) m_nSequenceMs = DEFAULT_SEQUENCE_MS; soundtouch_setSetting(handleSt, SETTING_SEQUENCE_MS, m_nSequenceMs); m_nSequenceMs = soundtouch_getSetting(handleSt, SETTING_SEQUENCE_MS); @@ -1996,7 +1962,7 @@ } // Keeps count of the sample length received from stretching process. - UINT nLengthCounter = 0; + SmpLength nLengthCounter = 0; // Process sample in steps. while(pos < sample.nLength) @@ -2041,7 +2007,7 @@ m_pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_replace); // Swap sample buffer pointer to new buffer, update song + sample data & free old sample buffer - ctrlSmp::ReplaceSample(sample, (LPSTR)pNewSample, min(nLengthCounter, nNewSampleLength), m_pSndFile); + ctrlSmp::ReplaceSample(sample, (LPSTR)pNewSample, Util::Min(nLengthCounter, nNewSampleLength), m_pSndFile); // Free progress bar brushes DeleteObject((HBRUSH)green); @@ -2610,7 +2576,7 @@ int n = GetDlgItemInt(IDC_EDIT14); if ((n >= lmin) && (n <= lmax)) { - m_pSndFile->GetSample(m_nSample).nVibSweep = (BYTE)n; + m_pSndFile->GetSample(m_nSample).nVibSweep = static_cast<uint8>(n); PropagateAutoVibratoChanges(); m_pModDoc->SetModified(); @@ -2645,14 +2611,14 @@ switch(n) { case 0: // Off - sample.uFlags &= ~(CHN_LOOP|CHN_PINGPONGLOOP|CHN_PINGPONGFLAG); + sample.uFlags &= ~(CHN_LOOP | CHN_PINGPONGLOOP); break; case 1: // On sample.uFlags &= ~CHN_PINGPONGLOOP; sample.uFlags |= CHN_LOOP; break; case 2: // PingPong - sample.uFlags |= CHN_LOOP|CHN_PINGPONGLOOP; + sample.uFlags |= CHN_LOOP | CHN_PINGPONGLOOP; break; } // set loop points if theren't any @@ -2726,14 +2692,14 @@ switch(n) { case 0: // Off - sample.uFlags &= ~(CHN_SUSTAINLOOP|CHN_PINGPONGSUSTAIN|CHN_PINGPONGFLAG); + sample.uFlags &= ~(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); break; case 1: // On sample.uFlags &= ~CHN_PINGPONGSUSTAIN; sample.uFlags |= CHN_SUSTAINLOOP; break; case 2: // PingPong - sample.uFlags |= CHN_SUSTAINLOOP|CHN_PINGPONGSUSTAIN; + sample.uFlags |= CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN; break; } // set sustain loop points if theren't any @@ -3170,12 +3136,16 @@ // Crossfade loop to create smooth loop transitions #define DEFAULT_XFADE_LENGTH 16384 //4096 -#define LimitXFadeLength(x) min(min(x, sample.nLoopEnd - sample.nLoopStart), sample.nLoopEnd / 2) +SmpLength LimitXFadeLength(SmpLength len, const ModSample &sample) +{ + return Util::Min(len, sample.nLoopEnd - sample.nLoopStart, sample.nLoopEnd / 2); +} + void CCtrlSamples::OnXFade() //-------------------------- { - static UINT nFadeLength = DEFAULT_XFADE_LENGTH; + static SmpLength fadeLength = DEFAULT_XFADE_LENGTH; ModSample &sample = m_pSndFile->GetSample(m_nSample); if(sample.pSample == nullptr) return; @@ -3183,23 +3153,23 @@ // Case 1: The loop start is preceeded by > XFADE_LENGTH samples. Nothing has to be adjusted. // Case 2: The actual loop is shorter than XFADE_LENGTH samples. // Case 3: There is not enough sample material before the loop start. Move the loop start. - nFadeLength = LimitXFadeLength(nFadeLength); + fadeLength = LimitXFadeLength(fadeLength, sample); - CSampleXFadeDlg dlg(this, nFadeLength, LimitXFadeLength(sample.nLength)); + CSampleXFadeDlg dlg(this, fadeLength, LimitXFadeLength(sample.nLength, sample)); if(dlg.DoModal() == IDOK) { - nFadeLength = dlg.m_nSamples; + fadeLength = dlg.m_nSamples; - if(nFadeLength < 4) return; + if(fadeLength < 4) return; - m_pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_update, sample.nLoopEnd - nFadeLength, sample.nLoopEnd); + m_pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_update, sample.nLoopEnd - fadeLength, sample.nLoopEnd); // If we want to fade nFadeLength bytes, we need as much sample material before the loop point. nFadeLength has been adjusted above. - if(sample.nLoopStart < nFadeLength) + if(sample.nLoopStart < fadeLength) { - sample.nLoopStart = nFadeLength; + sample.nLoopStart = fadeLength; } - if(ctrlSmp::XFadeSample(sample, nFadeLength, m_pSndFile)) + if(ctrlSmp::XFadeSample(sample, fadeLength, m_pSndFile)) { m_pModDoc->UpdateAllViews(NULL, (m_nSample << HINT_SHIFT_SMP) | HINT_SAMPLEDATA | HINT_SAMPLEINFO, NULL); m_pModDoc->SetModified(); Modified: trunk/OpenMPT/mptrack/Ctrl_smp.h =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.h 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/Ctrl_smp.h 2012-05-23 14:58:53 UTC (rev 1278) @@ -65,7 +65,7 @@ bool SetCurrentSample(SAMPLEINDEX nSmp, LONG lZoom = -1, bool bUpdNum = true); bool OpenSample(LPCSTR lpszFileName); - bool OpenSample(CSoundFile *pSndFile, SAMPLEINDEX nSample); + bool OpenSample(const CSoundFile *pSndFile, SAMPLEINDEX nSample); LONG* GetSplitPosRef() {return &CMainFrame::GetSettings().glSampleWindowHeight;} //rewbs.varWindowSize public: Modified: trunk/OpenMPT/mptrack/InputHandler.cpp =================================================================== --- trunk/OpenMPT/mptrack/InputHandler.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/InputHandler.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -294,7 +294,7 @@ if(MIDIEvents::GetTypeFromEvent(message) == MIDIEvents::evControllerChange && MIDIEvents::GetDataByte2FromEvent(message) != 0) { // Only capture MIDI CCs for now. Some controllers constantly send some MIDI CCs with value 0 - // (f.e. the Roland D-50 sends CC123 whenenver releasing note keys), so we will ignore those. + // (e.g. the Roland D-50 sends CC123 whenenver releasing note keys), so we will ignore those. return GeneralKeyEvent(context, HC_MIDI, MIDIEvents::GetDataByte1FromEvent(message), 0); } return kcNull; Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -2178,7 +2178,7 @@ ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CModDoc)) == TRUE); CModDoc* pModDoc = static_cast<CModDoc*>(pDoc); pModDoc->ClearFilePath(); // Clear path so that saving will not take place in templates/examples folder. - // Remove extension from title, so that saving the file will not suggest a filename like f.e. "template.mptm.mptm". + // Remove extension from title, so that saving the file will not suggest a filename like e.g. "template.mptm.mptm". const CString title = pModDoc->GetTitle(); const int dotPos = title.ReverseFind('.'); if(dotPos >= 0) Modified: trunk/OpenMPT/mptrack/SampleEditorDialogs.h =================================================================== --- trunk/OpenMPT/mptrack/SampleEditorDialogs.h 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/SampleEditorDialogs.h 2012-05-23 14:58:53 UTC (rev 1278) @@ -144,7 +144,7 @@ //=================================== { public: - UINT m_nSamples, m_nMaxSamples; + SmpLength m_nSamples, m_nMaxSamples; protected: CEdit m_EditSamples; Modified: trunk/OpenMPT/mptrack/Undo.cpp =================================================================== --- trunk/OpenMPT/mptrack/Undo.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/Undo.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -435,7 +435,7 @@ } // Restore old sample header - MemCopy(sample, undo.OldSample); + sample = undo.OldSample; sample.pSample = pCurrentSample; // select the "correct" old sample MemCopy(pSndFile->m_szNames[nSmp], undo.szOldName); Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -2297,7 +2297,7 @@ if ((m_findReplace.dwReplaceFlags & (PATSEARCH_VOLCMD | PATSEARCH_VOLUME)) && m->volcmd != VOLCMD_NONE) { - // Fix volume command parameters if necessary. This is necesary f.e. + // Fix volume command parameters if necessary. This is necesary e.g. // When there was a command "v24" and the user searched for v and replaced it by d. // In that case, d24 wouldn't be a valid command. DWORD minVal = 0, maxVal = 64; Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-05-23 14:58:53 UTC (rev 1278) @@ -477,10 +477,14 @@ > </File> <File - RelativePath="..\soundlib\Sampleio.cpp" + RelativePath="..\soundlib\SampleFormats.cpp" > </File> <File + RelativePath="..\soundlib\SampleIO.cpp" + > + </File> + <File RelativePath=".\serialization_utils.cpp" > </File> @@ -1135,10 +1139,18 @@ > </File> <File + RelativePath="..\soundlib\SampleFormatConverters.h" + > + </File> + <File RelativePath=".\SampleGenerator.h" > </File> <File + RelativePath="..\soundlib\SampleIO.h" + > + </File> + <File RelativePath=".\serialization_utils.h" > </File> @@ -1231,10 +1243,6 @@ > </File> <File - RelativePath="..\soundlib\wavConverter.h" - > - </File> - <File RelativePath="..\soundlib\WindowedFIR.h" > </File> @@ -1351,6 +1359,10 @@ Name="Module Loaders" > <File + RelativePath="..\soundlib\ChunkReader.h" + > + </File> + <File RelativePath="..\soundlib\ITTools.cpp" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-05-23 14:58:53 UTC (rev 1278) @@ -177,6 +177,8 @@ <ClCompile Include="..\soundlib\ModSample.cpp" /> <ClCompile Include="..\soundlib\plugins\JBridge.cpp" /> <ClCompile Include="..\soundlib\RowVisitor.cpp" /> + <ClCompile Include="..\soundlib\SampleFormats.cpp" /> + <ClCompile Include="..\soundlib\SampleIO.cpp" /> <ClCompile Include="..\soundlib\XMTools.cpp" /> <ClCompile Include="AbstractVstEditor.cpp" /> <ClCompile Include="ACMConvert.cpp" /> @@ -242,7 +244,6 @@ <ClCompile Include="..\soundlib\PlaybackEventer.cpp" /> <ClCompile Include="PSRatioCalc.cpp" /> <ClCompile Include="SampleEditorDialogs.cpp" /> - <ClCompile Include="..\soundlib\Sampleio.cpp" /> <ClCompile Include="ScaleEnvPointsDlg.cpp" /> <ClCompile Include="SelectPluginDialog.cpp" /> <ClCompile Include="serialization_utils.cpp" /> @@ -346,6 +347,8 @@ <ClInclude Include="..\soundlib\plugins\PluginMixBuffer.h" /> <ClInclude Include="..\soundlib\plugins\PlugInterface.h" /> <ClInclude Include="..\soundlib\RowVisitor.h" /> + <ClInclude Include="..\soundlib\SampleFormatConverters.h" /> + <ClInclude Include="..\soundlib\SampleIO.h" /> <ClInclude Include="..\soundlib\XMTools.h" /> <ClInclude Include="ACMConvert.h" /> <ClInclude Include="Autotune.h" /> @@ -440,7 +443,6 @@ <ClInclude Include="VSTEditor.h" /> <ClInclude Include="vstplug.h" /> <ClInclude Include="..\soundlib\Wav.h" /> - <ClInclude Include="..\soundlib\wavConverter.h" /> <ClInclude Include="..\soundlib\WindowedFIR.h" /> <ClInclude Include="..\soundlib\tuning.h" /> <ClInclude Include="..\soundlib\tuningbase.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-05-23 14:58:53 UTC (rev 1278) @@ -385,9 +385,6 @@ <ClCompile Include="MPTHacks.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\soundlib\Sampleio.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="Undo.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -460,6 +457,12 @@ <ClCompile Include="..\soundlib\MIDIEvents.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\soundlib\SampleIO.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\soundlib\SampleFormats.cpp"> + <Filter>Module Loaders</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -588,9 +591,6 @@ <ClInclude Include="..\soundlib\WindowedFIR.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\soundlib\wavConverter.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\soundlib\Wav.h"> <Filter>Header Files</Filter> </ClInclude> @@ -819,6 +819,12 @@ <ClInclude Include="..\soundlib\ChunkReader.h"> <Filter>Module Loaders</Filter> </ClInclude> + <ClInclude Include="..\soundlib\SampleIO.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\soundlib\SampleFormatConverters.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/mptrack/version.h 2012-05-23 14:58:53 UTC (rev 1278) @@ -56,7 +56,7 @@ strVersion = "Unknown"; } else if((v & 0xFFFF) == 0) { - // Only parts of the version number are known (f.e. when reading the version from the IT or S3M file header) + // Only parts of the version number are known (e.g. when reading the version from the IT or S3M file header) strVersion.Format("%X.%02X", (v >> 24) & 0xFF, (v >> 16) & 0xFF); } else { Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp =================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -28,7 +28,7 @@ #define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 /////////////////////////////////////////////////////////////////////////// -// Articulation connection graph definitions +// Articulation connection graph definitions // Generic Sources #define CONN_SRC_NONE 0x0000 @@ -79,7 +79,7 @@ #define MAKE_ART(src, ctl, dst) ( ((dst)<<16) | ((ctl)<<8) | (src) ) -// Vibrato / Tremolo +// Vibrato / Tremolo #define ART_LFO_FREQUENCY MAKE_ART (CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_FREQUENCY) #define ART_LFO_STARTDELAY MAKE_ART (CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_STARTDELAY) #define ART_LFO_ATTENUATION MAKE_ART (CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_ATTENUATION) @@ -890,7 +890,7 @@ } } break; - + #ifdef DLSINSTR_LOG default: { @@ -1117,7 +1117,7 @@ priff = (RIFFCHUNKID *)lpMemFile; dwMemPos = 0; - + // Check DLS sections embedded in RMI midi files if ((priff->id_RIFF == IFFID_RIFF) && (priff->id_DLS == IFFID_RMID)) { @@ -1345,7 +1345,7 @@ //--------------------------------------------------- { DLSINSTRUMENT *pDlsIns; - + if ((!m_pInstruments) || (nIns >= m_nInstruments)) return 0; pDlsIns = &m_pInstruments[nIns]; for (UINT rgn=0; rgn<pDlsIns->nRegions; rgn++) @@ -1450,7 +1450,7 @@ const float _factor = 128 * 12; const float _fct_100 = 128.0f / 100.0f; int result; - + if (!freq) return 0; _asm { fild nMidiFTune @@ -1475,7 +1475,7 @@ LPBYTE pWaveForm = NULL; DWORD dwLen = 0, dwWSMPOffset = 0; BOOL bOk, bWaveForm; - + if ((!m_pInstruments) || (nIns >= m_nInstruments) || (!pSndFile)) return FALSE; pDlsIns = &m_pInstruments[nIns]; if (nRgn >= pDlsIns->nRegions) return FALSE; @@ -1494,17 +1494,20 @@ #ifdef DLSINSTR_LOG Log(" SF2 WaveLink #%3d: %5dHz\n", nWaveLink, p->dwSampleRate); #endif + sample.Initialize(); sample.nLength = dwLen / 2; - sample.uFlags = CHN_16BIT; sample.nLoopStart = pDlsIns->Regions[nRgn].ulLoopStart; sample.nLoopEnd = pDlsIns->Regions[nRgn].ulLoopEnd; sample.nC5Speed = p->dwSampleRate; - sample.nGlobalVol = 64; - sample.nVolume = 256; - sample.nPan = 128; - pSndFile->ReadSample(&sample, RS_PCM16S, (LPSTR)pWaveForm, dwLen); sample.RelativeTone = p->byOriginalPitch; sample.nFineTune = p->chPitchCorrection; + + SampleIO( + SampleIO::_16bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(sample, (LPSTR)pWaveForm, dwLen); } bWaveForm = (sample.pSample) ? TRUE : FALSE; } else @@ -1610,7 +1613,7 @@ ModInstrument *pIns; UINT nRgnMin, nRgnMax, nEnv; SAMPLEINDEX nSample; - + if ((!m_pInstruments) || (nIns >= m_nInstruments) || (!pSndFile)) return FALSE; pDlsIns = &m_pInstruments[nIns]; if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS) @@ -1640,7 +1643,7 @@ Log(" usVolume = %3d, Unity Note = %d\n", prgn->usVolume, prgn->uUnityNote); } #endif - + try { pIns = new ModInstrument(); @@ -1916,4 +1919,4 @@ } } return nullptr; -} +} \ No newline at end of file Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -318,7 +318,7 @@ { mptIns.wMidiBank = LittleEndianW(mbank); } - + // Envelope point count. Limited to 25 in IT format. const int maxNodes = (modFormat & MOD_TYPE_MPT) ? MAX_ENVPOINTS : 25; @@ -523,7 +523,7 @@ if(mptSmp.nC5Speed < 256) mptSmp.nC5Speed = 256; // Size and loops - mptSmp.nLength = min(LittleEndian(length), MAX_SAMPLE_LENGTH); + mptSmp.nLength = LittleEndian(length); mptSmp.nLoopStart = LittleEndian(loopbegin); mptSmp.nLoopEnd = LittleEndian(loopend); mptSmp.nSustainStart = LittleEndian(susloopbegin); @@ -541,47 +541,50 @@ // Retrieve the internal sample format flags for this instrument. -UINT ITSample::GetSampleFormat(uint16 cwtv) const -//----------------------------------------------- +SampleIO ITSample::GetSampleFormat(uint16 cwtv) const +//--------------------------------------------------- { - UINT mptFlags = (cvt & ITSample::cvtSignedSample) ? RS_PCM8S : RS_PCM8U; + SampleIO sampleIO( + (flags & ITSample::sample16Bit) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + (cvt & ITSample::cvtSignedSample) ? SampleIO::signedPCM: SampleIO::unsignedPCM); - if(flags & ITSample::sample16Bit) + // Some old version of IT didn't clear the stereo flag when importing samples. Luckily, all other trackers are identifying as IT 2.14+, so let's check for old IT versions. + if((flags & ITSample::sampleStereo) && cwtv >= 0x214) { - // 16-Bit sample - mptFlags += 5; + sampleIO |= SampleIO::stereoSplit; + } - // Some old version of IT didn't clear the stereo flag when importing samples. Luckily, all other trackers are identifying as IT 2.14+, so let's check for old IT versions. - if((flags & ITSample::sampleStereo) && cwtv >= 0x214) - { - mptFlags |= RSF_STEREO; - } - - if(flags & ITSample::sampleCompressed) - { - // IT 2.14 16-bit packed sample - mptFlags = (cvt & ITSample::cvtIT215Compression) ? RS_IT21516 : RS_IT21416; - } + if(flags & ITSample::sampleCompressed) + { + // IT 2.14 packed sample + sampleIO |= (cvt & ITSample::cvtIT215Compression) ? SampleIO::IT215 : SampleIO::IT214; } else { - // 8-Bit sample - // Some old version of IT didn't clear the stereo flag when importing samples. Luckily, all other trackers are identifying as IT 2.14+, so let's check for old IT versions. - if((flags & ITSample::sampleStereo) && cwtv >= 0x214) + // MODPlugin :( + if(!(flags & ITSample::sample16Bit) && cvt == ITSample::cvtADPCMSample) { - mptFlags |= RSF_STEREO; - } - - if(cvt == ITSample::cvtADPCMSample) + sampleIO |= SampleIO::ADPCM; + } else { - mptFlags = RS_ADPCM4; - } else if(flags & ITSample::sampleCompressed) - { - // IT 2.14 8-bit packed sample? - mptFlags = (cvt & ITSample::cvtIT215Compression) ? RS_IT2158 : RS_IT2148; + // ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :) + if(cvt & ITSample::cvtBigEndian) + { + sampleIO |= SampleIO::bigEndian; + } + if(cvt & ITSample::cvtDelta) + { + sampleIO |= SampleIO::deltaPCM; + } + if((cvt & ITSample::cvtPTM8to16) && (flags & ITSample::sample16Bit)) + { + sampleIO |= SampleIO::PTM8Dto16; + } } } - return mptFlags; + return sampleIO; } @@ -621,4 +624,4 @@ SwapBytesLE(runtime); } -#endif // MODPLUG_TRACKER +#endif // MODPLUG_TRACKER \ No newline at end of file Modified: trunk/OpenMPT/soundlib/ITTools.h =================================================================== --- trunk/OpenMPT/soundlib/ITTools.h 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/ITTools.h 2012-05-23 14:58:53 UTC (rev 1278) @@ -17,7 +17,7 @@ // Magic Bytes enum Magic { - itMagic = 0x4D504D49, // "IMPM" IT Header Magic Bytes + itMagic = 0x4D504D49, // "IMPM" IT Header Magic Bytes mptmMagic = 0x2E6D7074, // "tpm." Old MPTM header magic bytes omptMagic = 0x54504D4F, // "OMPT" Magic Bytes for non-standard OpenMPT IT files chibiMagic = 0x49424843, // "CHBI" Magic Bytes in the IT header to identify ChibiTracker @@ -247,6 +247,11 @@ cvtSignedSample = 0x01, cvtIT215Compression = 0x04, cvtADPCMSample = 0xFF, // MODPlugin :( + + // ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :) + cvtBigEndian = 0x02, + cvtDelta = 0x04, + cvtPTM8to16 = 0x08, }; uint32 id; // Magic Bytes (IMPS) @@ -274,7 +279,7 @@ // Convert an ITSample to OpenMPT's internal sample representation. size_t ConvertToMPT(ModSample &mptSmp) const; // Retrieve the internal sample format flags for this instrument. - UINT GetSampleFormat(uint16 cwtv = 0x214) const; + SampleIO GetSampleFormat(uint16 cwtv = 0x214) const; }; STATIC_ASSERT(sizeof(ITSample) == 80); @@ -323,4 +328,4 @@ IT_bitmask_patternChanMask_c = 0x3f, IT_bitmask_patternChanEnabled_c = 0x80, IT_bitmask_patternChanUsed_c = 0x0f -}; +}; \ No newline at end of file Modified: trunk/OpenMPT/soundlib/LOAD_AMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_AMF.CPP 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/LOAD_AMF.CPP 2012-05-23 14:58:53 UTC (rev 1278) @@ -169,7 +169,7 @@ { const AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream; DWORD dwMemPos; - + if ((!lpStream) || (dwMemLength < 2048)) return false; if ((!strncmp((LPCSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096)) { @@ -244,14 +244,21 @@ } dwMemPos += 64*32; } + // Read samples + const SampleIO sampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM); + for (UINT iData=0; iData<m_nSamples; iData++) { - ModSample *psmp = &Samples[iData+1]; - if (psmp->nLength) + ModSample &sample = Samples[iData + 1]; + if(sample.nLength) { if(dwMemPos > dwMemLength) return false; - dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos); + dwMemPos += sampleIO.ReadSample(sample, (LPCSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos); } } return true; @@ -350,7 +357,7 @@ if ((psh->type) && (LittleEndian(psh->offset) < dwMemLength-1)) { sampleseekpos[iIns] = LittleEndian(psh->offset); - if (LittleEndian(psh->offset) > maxsampleseekpos) + if (LittleEndian(psh->offset) > maxsampleseekpos) maxsampleseekpos = LittleEndian(psh->offset); if ((pSmp->nLoopEnd > pSmp->nLoopStart + 2) && (pSmp->nLoopEnd <= pSmp->nLength)) pSmp->uFlags |= CHN_LOOP; @@ -402,17 +409,20 @@ } // Read Sample Data + const SampleIO sampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::unsignedPCM); + for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++) { if (dwMemPos >= dwMemLength) break; for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp]) { - ModSample *pSmp = &Samples[iSmp+1]; - dwMemPos += ReadSample(pSmp, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); + dwMemPos += sampleIO.ReadSample(Samples[iSmp + 1], (LPCSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos); break; } } return true; } - - Modified: trunk/OpenMPT/soundlib/LOAD_DBM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-05-23 14:58:53 UTC (rev 1278) @@ -188,7 +188,7 @@ const DBMFileHeader *pfh = (DBMFileHeader *)lpStream; DWORD dwMemPos; uint16 nOrders, nSamples, nInstruments, nPatterns; - + 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) @@ -223,7 +223,7 @@ uint32 chunk_id = LittleEndian(((uint32 *)(lpStream + dwMemPos))[0]); uint32 chunk_size = BigEndian(((uint32 *)(lpStream + dwMemPos))[1]); uint32 chunk_pos; - + dwMemPos += 8; chunk_pos = dwMemPos; if ((dwMemPos + chunk_size > dwMemLength) || (chunk_size > dwMemLength)) break; @@ -294,13 +294,13 @@ if (chunk_id == DBM_ID_VENV) { UINT nEnvelopes = lpStream[chunk_pos+1]; - + chunk_pos += 2; for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++) { DBMEnvelope *peh; UINT nins; - + if (chunk_pos + sizeof(DBMEnvelope) > dwMemPos) break; peh = (DBMEnvelope *)(lpStream+chunk_pos); nins = BigEndianW(peh->instrument); @@ -448,7 +448,6 @@ m_nSamples = nSamples; for (UINT iSmp=1; iSmp<=nSamples; iSmp++) { - ModSample *pSmp; DBMSample *psh; DWORD samplesize; DWORD sampleflags; @@ -458,23 +457,30 @@ chunk_pos += 8; samplesize = BigEndian(psh->samplesize); sampleflags = BigEndian(psh->flags); - pSmp = &Samples[iSmp]; - pSmp->nLength = samplesize; - if (sampleflags & 2) + + ModSample &sample = Samples[iSmp]; + sample.nLength = samplesize; + if(sampleflags & 2) { - pSmp->uFlags |= CHN_16BIT; - samplesize <<= 1; + samplesize *= 2; } - if ((chunk_pos+samplesize > dwMemPos) || (samplesize > dwMemLength)) break; - if (sampleflags & 3) + if(chunk_pos + samplesize > dwMemPos || samplesize > dwMemLength) { - ReadSample(pSmp, (pSmp->uFlags & CHN_16BIT) ? RS_PCM16M : RS_PCM8S, - (LPSTR)(psh->sampledata), samplesize); + break; } + + if(sampleflags & 3) + { + SampleIO( + (sampleflags & 2) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::bigEndian, + SampleIO::signedPCM) + .ReadSample(sample, (LPSTR)(psh->sampledata), samplesize); + } chunk_pos += samplesize; } } } return true; } - Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-05-23 14:58:53 UTC (rev 1278) @@ -246,7 +246,7 @@ } globalInfo &= DMFPAT_GLOBMASK; - + uint8 globalData = 0; if(globalInfo != 0) { @@ -759,7 +759,7 @@ ModSample &sample = pSndFile->GetSample(nSmp); MemsetZero(sample); - sample.nLength = min(MAX_SAMPLE_LENGTH, LittleEndian(smpHead->length)); + sample.nLength = LittleEndian(smpHead->length); sample.nSustainEnd = min(sample.nLength, LittleEndian(smpHead->loopEnd)); sample.nSustainStart = min(sample.nSustainEnd, LittleEndian(smpHead->loopStart)); if(sample.nSustainEnd > 0) @@ -950,12 +950,13 @@ if(length > 0) { - UINT flags = (Samples[nSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; - if((sampleFlags[nSmp - 1] & DMFSMP_COMPMASK) == DMFSMP_COMP1) - { - flags = (Samples[nSmp].uFlags & CHN_16BIT) ? RS_DMF16 : RS_DMF8; - } - ReadSample(&Samples[nSmp], flags, (LPCSTR)(lpStream + dwMemPos), length); + SampleIO( + (Samples[nSmp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + ((sampleFlags[nSmp - 1] & DMFSMP_COMPMASK) == DMFSMP_COMP1) ? SampleIO::DMF : SampleIO::signedPCM) + .ReadSample(Samples[nSmp], (LPCSTR)(lpStream + dwMemPos), length); + dwMemPos += length; } } @@ -1033,7 +1034,7 @@ typedef struct DMF_HTREE { - uint8 *ibuf, *ibufmax; + const uint8 *ibuf, *ibufmax; uint32 bitbuf; int bitnum; int lastnode, nodecount; @@ -1102,13 +1103,13 @@ } -int DMFUnpack(LPBYTE psample, uint8 *ibuf, uint8 *ibufmax, UINT maxlen) -//--------------------------------------------------------------------- +int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, UINT maxlen) +//--------------------------------------------------------------------------------- { DMF_HTREE tree; int actnode; uint8 value, sign, delta = 0; - + MemsetZero(tree); tree.ibuf = ibuf; tree.ibufmax = ibufmax; @@ -1139,4 +1140,3 @@ return tree.ibuf - ibuf; } - Modified: trunk/OpenMPT/soundlib/LOAD_DSM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DSM.CPP 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/LOAD_DSM.CPP 2012-05-23 14:58:53 UTC (rev 1278) @@ -216,21 +216,27 @@ DWORD dwPos = dwMemPos + sizeof(DSMSAMPLE); dwMemPos += 8 + pSmp->inst_len; - ModSample *psmp = &Samples[nSmp]; + ModSample &sample = Samples[nSmp]; + sample.Initialize(); StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[nSmp], pSmp->samplename); - StringFixer::ReadString<StringFixer::nullTerminated>(psmp->filename, pSmp->filename); + StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, pSmp->filename); - psmp->nGlobalVol = 64; - psmp->nC5Speed = pSmp->c2spd; - psmp->uFlags = (WORD)((pSmp->flags & 1) ? CHN_LOOP : 0); - psmp->nLength = pSmp->length; - psmp->nLoopStart = pSmp->loopstart; - psmp->nLoopEnd = pSmp->loopend; - psmp->nVolume = (WORD)(pSmp->volume << 2); - if (psmp->nVolume > 256) psmp->nVolume = 256; - UINT smptype = (pSmp->flags & 2) ? RS_PCM8S : RS_PCM8U; - ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos); + sample.nC5Speed = pSmp->c2spd; + sample.uFlags = (WORD)((pSmp->flags & 1) ? CHN_LOOP : 0); + sample.nLength = pSmp->length; + sample.nLoopStart = pSmp->loopstart; + sample.nLoopEnd = pSmp->loopend; + sample.nVolume = (WORD)(pSmp->volume << 2); + if (sample.nVolume > 256) sample.nVolume = 256; + + SampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + (pSmp->flags & 2) ? SampleIO::signedPCM : SampleIO::unsignedPCM) + .ReadSample(sample, (LPCSTR)(lpStream + dwPos), dwMemLength - dwPos); + nSmp++; } else { @@ -239,4 +245,3 @@ } return true; } - Modified: trunk/OpenMPT/soundlib/Load_669.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_669.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_669.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -66,7 +66,7 @@ //---------------------------------------- { _669FileHeader fileHeader; - + file.Rewind(); if(!file.ReadConvertEndianness(fileHeader)) { @@ -105,7 +105,6 @@ SmpLength len = sample.length; SmpLength loopstart = sample.loopStart; SmpLength loopend = sample.loopEnd; - if(len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH; if((loopend > len) && (!loopstart)) loopend = 0; if(loopend > len) loopend = len; if(loopstart + 4 >= loopend) loopstart = loopend = 0; @@ -215,9 +214,15 @@ } // Reading Samples + const SampleIO sampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::unsignedPCM); + for(SAMPLEINDEX n = 1; n <= m_nSamples; n++) { - ReadSample(&Samples[n], RS_PCM8U, file); + sampleIO.ReadSample(Samples[n], file); } return true; -} +} \ No newline at end of file Modified: trunk/OpenMPT/soundlib/Load_ams.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_ams.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -77,7 +77,7 @@ AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream; DWORD dwMemPos; UINT tmp, tmp2; - + if ((!lpStream) || (dwMemLength < 126)) return false; if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7)) || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples >= MAX_SAMPLES) @@ -113,9 +113,12 @@ if (dwMemPos + 1 >= dwMemLength) return true; tmp = lpStream[dwMemPos++]; if (dwMemPos + tmp >= dwMemLength) return true; - StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); + if(tmp) + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); + dwMemPos += tmp; + } - dwMemPos += tmp; // Read sample names for (UINT sNam=1; sNam<=m_nSamples; sNam++) @@ -123,8 +126,11 @@ if (dwMemPos + 1 >= dwMemLength) return true; tmp = lpStream[dwMemPos++]; if (dwMemPos + tmp >= dwMemLength) return true; - StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[sNam], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); - dwMemPos += tmp; + if(tmp) + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[sNam], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); + dwMemPos += tmp; + } } // Read Channel names @@ -133,8 +139,11 @@ 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; + if(chnnamlen) + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(ChnSettings[cNam].szName, reinterpret_cast<const char *>(lpStream + dwMemPos), chnnamlen); + dwMemPos += chnnamlen; + } } // Read Pattern Names @@ -151,7 +160,7 @@ } dwMemPos += tmp; } - + // Read Song Comments tmp = *((WORD *)(lpStream+dwMemPos)); dwMemPos += 2; @@ -274,8 +283,12 @@ for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Samples[iSmp].nLength) { if (dwMemPos >= dwMemLength - 9) return true; - UINT flags = (Samples[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8; - dwMemPos += ReadSample(&Samples[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); + dwMemPos += SampleIO( + (Samples[iSmp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::AMS) + .ReadSample(Samples[iSmp], (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); } return true; } @@ -395,7 +408,7 @@ { return true; } - + MemsetZero(smpmap); for (UINT ismpmap=0; ismpmap<pSmp->samples; ismpmap++) @@ -577,15 +590,13 @@ for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Samples[iSmp].nLength) { if (dwMemPos >= dwMemLength - 9) return true; - UINT flags; - if (packedsamples[iSmp] & 0x03) - { - flags = (Samples[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8; - } else - { - flags = (Samples[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; - } - dwMemPos += ReadSample(&Samples[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); + + dwMemPos += SampleIO( + (Samples[iSmp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + (packedsamples[iSmp] & 0x03) ? SampleIO::AMS, SampleIO::signedPCM) + .ReadSample(Samples[iSmp], format, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); } return true; #endif @@ -600,7 +611,7 @@ { UINT tmplen = dmax; signed char *amstmp = new signed char[tmplen]; - + if (!amstmp) return; // Unpack Loop { @@ -661,4 +672,3 @@ } delete[] amstmp; } - Modified: trunk/OpenMPT/soundlib/Load_far.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_far.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_far.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -118,7 +118,7 @@ Order.ReadFromArray(pmh2->orders, pmh2->snglen); m_nRestartPos = pmh2->loopto; - // Reading Patterns + // Reading Patterns dwMemPos += headerlen - (869 + pmh1->stlen); if (dwMemPos >= dwMemLength) return true; @@ -241,40 +241,45 @@ if (dwMemPos + 8 >= dwMemLength) return true; memcpy(samplemap, lpStream+dwMemPos, 8); dwMemPos += 8; - ModSample *pSmp = &Samples[1]; - for (UINT ismp=0; ismp<64; ismp++, pSmp++) if (samplemap[ismp >> 3] & (1 << (ismp & 7))) + for(UINT ismp=0; ismp<64; ismp++) if (samplemap[ismp >> 3] & (1 << (ismp & 7))) { if (dwMemPos + sizeof(FARSAMPLE) > dwMemLength) return true; const FARSAMPLE *pfs = reinterpret_cast<const FARSAMPLE*>(lpStream + dwMemPos); dwMemPos += sizeof(FARSAMPLE); m_nSamples = ismp + 1; - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[ismp+1], pfs->samplename); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[ismp + 1], pfs->samplename); + ModSample &sample = Samples[ismp + 1]; + sample.Initialize(); + const DWORD length = LittleEndian(pfs->length); - pSmp->nLength = length; - pSmp->nLoopStart = LittleEndian(pfs->reppos) ; - pSmp->nLoopEnd = LittleEndian(pfs->repend) ; - pSmp->nFineTune = 0; - pSmp->nC5Speed = 8363*2; - pSmp->nGlobalVol = 64; - pSmp->nVolume = pfs->volume << 4; - pSmp->uFlags = 0; - if ((pSmp->nLength > 3) && (dwMemPos + 4 < dwMemLength)) + sample.nLength = length; + sample.nLoopStart = LittleEndian(pfs->reppos); + sample.nLoopEnd = LittleEndian(pfs->repend); + sample.nC5Speed = 8363 * 2; + sample.nVolume = pfs->volume << 4; + + if((sample.nLength > 3) && (dwMemPos + 4 < dwMemLength)) { - if (pfs->type & 1) + SampleIO sampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM); + + if(pfs->type & 1) { - pSmp->uFlags |= CHN_16BIT; - pSmp->nLength >>= 1; - pSmp->nLoopStart >>= 1; - pSmp->nLoopEnd >>= 1; + sampleIO |= SampleIO::_16bit; + sample.nLength >>= 1; + sample.nLoopStart >>= 1; + sample.nLoopEnd >>= 1; } - if ((pfs->loop & 8) && (pSmp->nLoopEnd > 4)) pSmp->uFlags |= CHN_LOOP; - ReadSample(pSmp, (pSmp->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S, - (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos); + if ((pfs->loop & 8) && (sample.nLoopEnd > 4)) sample.uFlags |= CHN_LOOP; + + sampleIO.ReadSample(sample, (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos); } dwMemPos += length; } return true; } - Modified: trunk/OpenMPT/soundlib/Load_gdm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_gdm.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_gdm.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -158,7 +158,7 @@ for(CHANNELINDEX i = 0; i < 32; i++) { if(fileHeader.panMap[i] < 16) - { + { ChnSettings[i].nPan = min((fileHeader.panMap[i] * 16) + 8, 256); } else if(fileHeader.panMap[i] == 16) @@ -209,7 +209,7 @@ Samples[smp].nC5Speed = gdmSample.c4Hertz; Samples[smp].nGlobalVol = 256; // Not supported in this format - Samples[smp].nLength = min(gdmSample.length, MAX_SAMPLE_LENGTH); // in bytes + Samples[smp].nLength = gdmSample.length; // in bytes // Sample format if(gdmSample.flags & GDMSampleHeader::smp16Bit) @@ -267,9 +267,14 @@ // Read sample data if(file.Seek(fileHeader.sampleDataOffset)) { - for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { - ReadSample(&Samples[smp], (Samples[smp].uFlags & CHN_16BIT) ? RS_PCM16U : RS_PCM8U, file); + SampleIO( + (Samples[smp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::unsignedPCM) + .ReadSample(Samples[smp], file); } } @@ -402,7 +407,7 @@ m.param &= 0xF0; break; - case CMD_VOLUME: + case CMD_VOLUME: m.param = min(m.param, 64); if(modSpecs.HasVolCommand(VOLCMD_VOLUME)) { @@ -499,12 +504,12 @@ } } - + } } } - // Read song comments + // Read song comments if(fileHeader.messageTextLength > 0 && file.Seek(fileHeader.messageTextOffset)) { ReadMessage(file, fileHeader.messageTextLength, leAutodetect); @@ -512,4 +517,4 @@ return true; -} +} \ No newline at end of file Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -304,7 +304,7 @@ m_nSamples = 0; // Will be incremented later m_nInstruments = 0; - + m_nChannels = 0; for(CHANNELINDEX nChn = 0; nChn < 32; nChn++) { @@ -349,7 +349,7 @@ Order.resize(hdr.ordnum); for(ORDERINDEX nOrd = 0; nOrd < hdr.ordnum; nOrd++) Order[nOrd] = ((hdr.orderlist[nOrd] == 0xFF) ? Order.GetIgnoreIndex() : (PATTERNINDEX)hdr.orderlist[nOrd]); - + // read patterns for(PATTERNINDEX nPat = 0; nPat < hdr.patnum; nPat++) { @@ -491,7 +491,7 @@ // Orpheus does not check this! //if(memcmp(imfins.ii10, "II10", 4) != 0) // return false; - + try { pIns = new ModInstrument(); @@ -536,7 +536,7 @@ if(memcmp(imfsmp.is10, "IS10", 4) != 0) return false; - + ModSample &sample = Samples[firstsample + nSmp]; sample.Initialize(); @@ -562,17 +562,23 @@ } if(imfsmp.flags & 8) sample.uFlags |= CHN_PANNING; - + if(byteLen) { ASSERT_CAN_READ(byteLen); - ReadSample(&sample, (imfsmp.flags & 4) ? RS_PCM16S : RS_PCM8S, reinterpret_cast<LPCSTR>(lpStream + dwMemPos), byteLen); + + SampleIO( + (imfsmp.flags & 4) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(sample, reinterpret_cast<LPCSTR>(lpStream + dwMemPos), byteLen); } dwMemPos += byteLen; } firstsample += imfins.smpnum; } - + return true; } \ No newline at end of file Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -764,7 +764,7 @@ 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)); + lastSampleOffset = Util::Max(lastSampleOffset, sampleOffset + pis->GetSampleFormat(itHeader.cwtv).ReadSample(Samples[nsmp + 1], (LPSTR)(lpStream + sampleOffset), dwMemLength - sampleOffset)); } } m_nSamples = max(1, m_nSamples); @@ -1538,7 +1538,7 @@ fseek(f, dwPos, SEEK_SET); if ((Samples[nsmp].pSample) && (Samples[nsmp].nLength)) { - dwPos += WriteSample(f, &Samples[nsmp], itss.GetSampleFormat()); + dwPos += itss.GetSampleFormat().WriteSample(f, Samples[nsmp]); } } @@ -1617,8 +1617,8 @@ ////////////////////////////////////////////////////////////////////////////// // IT 2.14 compression -DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n) -//----------------------------------------------------------------- +DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, const uint8 *(&ibuf), CHAR n) +//------------------------------------------------------------------------- { DWORD retval = 0; UINT i = n; @@ -1643,11 +1643,12 @@ return (retval >> (32-i)); } -void ITUnpack8Bit(LPSTR pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215) -//------------------------------------------------------------------------------------------- + +void ITUnpack8Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215) +//-------------------------------------------------------------------------------------------------- { LPSTR pDst = pSample; - LPBYTE pSrc = lpMemFile; + const uint8 *pSrc = lpMemFile; DWORD wHdr = 0; DWORD wCount = 0; DWORD bitbuf = 0; @@ -1707,7 +1708,7 @@ wBits += bTemp; bTemp = (BYTE)wBits; bTemp2 += bTemp; - pDst[dwPos] = (b215) ? bTemp2 : bTemp; + pDst[dwPos] = (it215) ? bTemp2 : bTemp; SkipByte: dwPos++; @@ -1722,11 +1723,11 @@ } -void ITUnpack16Bit(LPSTR pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215) -//-------------------------------------------------------------------------------------------- +void ITUnpack16Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215) +//--------------------------------------------------------------------------------------------------- { signed short *pDst = (signed short *)pSample; - LPBYTE pSrc = lpMemFile; + const uint8 *pSrc = lpMemFile; DWORD wHdr = 0; DWORD wCount = 0; DWORD bitbuf = 0; @@ -1787,7 +1788,7 @@ dwBits += wTemp; wTemp = (signed short)dwBits; wTemp2 += wTemp; - pDst[dwPos] = (b215) ? wTemp2 : wTemp; + pDst[dwPos] = (it215) ? wTemp2 : wTemp; SkipByte: dwPos++; @@ -2510,7 +2511,7 @@ // move forward one byte and try to recognize again. memPos++; modularData++; - + } } //end rewbs.modularInstData @@ -2518,4 +2519,4 @@ return modularInstSize; #undef ASSERT_CAN_READ_INSTR -} +} \ No newline at end of file Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2012-05-22 00:27:08 UTC (rev 1277) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2012-05-23 14:58:53 UTC (rev 1278) @@ -339,7 +339,7 @@ StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[nsmp], pis.name); // Read sample data - ReadSample(&Samples[nsmp], pis.GetSampleFormat(), (LPSTR)(lpStream + dwMemPos), len); + pis.GetSampleFormat().ReadSample(Samples[nsmp], (LPSTR)(lpStream + dwMemPos), len); dwMemPos += len; } } @@ -360,7 +360,7 @@ ReadInstrumentFromFile(i+1, lpFile, len); f.Unlock(); - f.Close(); + f.Close(); } // Extra info data @@ -389,7 +389,7 @@ switch( fcode ) { - case 'MPTS': goto mpts; //:) // reached end of instrument headers + case 'MPTS': goto mpts; //:) // reached end of instrument headers case 'SEP@': case 'MPTX': ptr += sizeof(__int32); // jump code i++; // switch to next instrument @@ -629,10 +629,9 @@ itss.samplepointer = 0; fwrite(&itss, 1, sizeof(itss), f); - UINT flags = itss.GetSampleFormat(); - id = WriteSample(nullptr, &Samples[nsmp], flags); + id = Samples[nsmp].GetSa... [truncated message content] |
From: <sag...@us...> - 2012-05-23 15:28:05
|
Revision: 1279 http://modplug.svn.sourceforge.net/modplug/?rev=1279&view=rev Author: saga-games Date: 2012-05-23 15:27:52 +0000 (Wed, 23 May 2012) Log Message: ----------- [Fix] An order list beginning with a separator and a stop pattern shouldn't hang the tracker anymore (http://bugs.openmpt.org/view.php?id=255). [Mod] OpenMPT: Version is now 1.20.01.03 Modified Paths: -------------- trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-05-23 14:58:53 UTC (rev 1278) +++ trunk/OpenMPT/mptrack/version.h 2012-05-23 15:27:52 UTC (rev 1279) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 02 +#define VER_MINORMINOR 03 //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/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-05-23 14:58:53 UTC (rev 1278) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-05-23 15:27:52 UTC (rev 1279) @@ -1450,11 +1450,10 @@ // Convert sample rate to integer uint32 GetSampleRate() const { - uint32 mantissa, last = 0; - uint8 exp; + uint32 mantissa = *reinterpret_cast<const uint32 *>(&sampleRate[2]), last = 0; + uint8 exp = 30 - sampleRate[1]; + SwapBytesBE(mantissa); - mantissa = SwapBytesBE(static_cast<uint32 >(*reinterpret_cast<const uint32 *>(sampleRate + 2))); - exp = 30 - sampleRate[1]; while(exp--) { last = mantissa; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-05-23 14:58:53 UTC (rev 1278) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-05-23 15:27:52 UTC (rev 1279) @@ -200,7 +200,10 @@ { // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. memory.Reset(); - continue; + nRow = nNextRow; + nCurrentOrder = nNextOrder; + nPattern = Order[nCurrentOrder]; + break; } } } @@ -4617,4 +4620,4 @@ pChn->nOldFinePortaUpDown = abs(tickParam); pChn->m_CalculateFreq = true; -} \ No newline at end of file +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-24 17:31:03
|
Revision: 1280 http://modplug.svn.sourceforge.net/modplug/?rev=1280&view=rev Author: saga-games Date: 2012-05-24 17:30:56 +0000 (Thu, 24 May 2012) Log Message: ----------- [Mod] Added some tests for sample loading code. [Mod] Changed some sample conversion functors a bit. Modified Paths: -------------- trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/soundlib/SampleFormatConverters.h Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-05-23 15:27:52 UTC (rev 1279) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-05-24 17:30:56 UTC (rev 1280) @@ -11,6 +11,15 @@ #include "stdafx.h" #include "test.h" + + +#ifdef _DEBUG + #define new DEBUG_NEW +#endif + +#ifdef ENABLE_TESTS + + #include "../mptrack.h" #include "../moddoc.h" #include "../MainFrm.h" @@ -20,17 +29,12 @@ #include "../../common/misc_util.h" #include "../../common/StringFixer.h" #include "../serialization_utils.h" +#include "../../soundlib/SampleFormatConverters.h" #include <limits> #include <fstream> #include <strstream> -#ifdef _DEBUG - #define new DEBUG_NEW -#endif - -#ifdef ENABLE_TESTS - namespace MptTest { @@ -78,6 +82,7 @@ void TestMisc(); void TestMIDIEvents(); void TestStringIO(); +void TestSampleConversion(); @@ -92,6 +97,7 @@ DO_TEST(TestMIDIEvents); DO_TEST(TestLoadSaveFile); DO_TEST(TestStringIO); + DO_TEST(TestSampleConversion); Log(TEXT("Tests were run\n")); } @@ -1176,6 +1182,181 @@ } + +void TestSampleConversion() +//------------------------- +{ + uint8 *sourceBuf = new uint8[65536 * 4]; + void *targetBuf = new uint8[65536 * 6]; + + + // Signed 8-Bit Integer PCM + // Unsigned 8-Bit Integer PCM + // Delta 8-Bit Integer PCM + { + uint8 *source8 = sourceBuf; + for(size_t i = 0; i < 256; i++) + { + source8[i] = static_cast<uint8>(i); + } + + int8 *signed8 = static_cast<int8 *>(targetBuf); + uint8 *unsigned8 = static_cast<uint8 *>(targetBuf) + 256; + int8 *delta8 = static_cast<int8 *>(targetBuf) + 512; + int8 delta = 0; + CopySample<ReadInt8PCM<0> >(signed8, 256, 1, source8, 256, 1); + CopySample<ReadInt8PCM<0x80u> >(unsigned8, 256, 1, source8, 256, 1); + CopySample<ReadInt8DeltaPCM>(delta8, 256, 1, source8, 256, 1); + + for(size_t i = 0; i < 256; i++) + { + delta += static_cast<int8>(i); + VERIFY_EQUAL_NONCONT(signed8[i], static_cast<int8>(i)); + VERIFY_EQUAL_NONCONT(unsigned8[i], static_cast<uint8>(i + 0x80u)); + VERIFY_EQUAL_NONCONT(delta8[i], static_cast<int8>(delta)); + } + } + + // Signed 16-Bit Integer PCM + // Unsigned 16-Bit Integer PCM + // Delta 16-Bit Integer PCM + { + // Little Endian + + uint8 *source16 = sourceBuf; + for(size_t i = 0; i < 65536; i++) + { + source16[i * 2 + 0] = static_cast<uint8>(i & 0xFF); + source16[i * 2 + 1] = static_cast<uint8>(i >> 8); + } + + int16 *signed16 = static_cast<int16 *>(targetBuf); + uint16 *unsigned16 = static_cast<uint16 *>(targetBuf) + 65536; + int16 *delta16 = static_cast<int16 *>(targetBuf) + 65536 * 2; + int16 delta = 0; + CopySample<ReadInt16PCM<0, littleEndian16> >(signed16, 65536, 1, source16, 65536 * 2, 1); + CopySample<ReadInt16PCM<0x8000u, littleEndian16> >(unsigned16, 65536, 1, source16, 65536 * 2, 1); + CopySample<ReadInt16DeltaPCM<littleEndian16> >(delta16, 65536, 1, source16, 65536 * 2, 1); + + for(size_t i = 0; i < 65536; i++) + { + delta += static_cast<int16>(i); + VERIFY_EQUAL_NONCONT(signed16[i], static_cast<int16>(i)); + VERIFY_EQUAL_NONCONT(unsigned16[i], static_cast<uint16>(i + 0x8000u)); + VERIFY_EQUAL_NONCONT(delta16[i], static_cast<int16>(delta)); + } + + // Big Endian + + for(size_t i = 0; i < 65536; i++) + { + source16[i * 2 + 0] = static_cast<uint8>(i >> 8); + source16[i * 2 + 1] = static_cast<uint8>(i & 0xFF); + } + + CopySample<ReadInt16PCM<0, bigEndian16> >(signed16, 65536, 1, source16, 65536 * 2, 1); + CopySample<ReadInt16PCM<0x8000u, bigEndian16> >(unsigned16, 65536, 1, source16, 65536 * 2, 1); + CopySample<ReadInt16DeltaPCM<bigEndian16> >(delta16, 65536, 1, source16, 65536 * 2, 1); + + delta = 0; + for(size_t i = 0; i < 65536; i++) + { + delta += static_cast<int16>(i); + VERIFY_EQUAL_NONCONT(signed16[i], static_cast<int16>(i)); + VERIFY_EQUAL_NONCONT(unsigned16[i], static_cast<uint16>(i + 0x8000u)); + VERIFY_EQUAL_NONCONT(delta16[i], static_cast<int16>(delta)); + } + + } + + // Signed 24-Bit Integer PCM + { + uint8 *source24 = sourceBuf; + for(size_t i = 0; i < 65536; i++) + { + source24[i * 3 + 0] = 0; + source24[i * 3 + 1] = static_cast<uint8>(i & 0xFF); + source24[i * 3 + 2] = static_cast<uint8>(i >> 8); + } + + int16 *truncated16 = static_cast<int16 *>(targetBuf); + ModSample sample; + sample.Initialize(); + sample.nLength = 65536; + sample.uFlags |= CHN_16BIT; + sample.pSample = (LPSTR)(static_cast<int16 *>(targetBuf) + 65536); + CopyAndNormalizeSample<ReadBigIntToInt16PCMandNormalize<ReadInt24to32PCM<0, littleEndian24> > >(sample, reinterpret_cast<const uint8 *>(source24), sizeof(source24)); + CopySample<ReadBigIntTo16PCM<3, 1, 2> >(truncated16, 65536, 1, source24, 65536 * 3, 1); + + for(size_t i = 0; i < 65536; i++) + { + int16 normValue = reinterpret_cast<const int16 *>(sample.pSample)[i]; + if(abs(normValue - static_cast<int16>(i - 0x8000u)) > 1) + { + VERIFY_EQUAL_NONCONT(true, false); + } + VERIFY_EQUAL_NONCONT(truncated16[i], static_cast<int16>(i)); + } + } + + // Float 32-Bit + { + uint8 *source32 = sourceBuf; + for(size_t i = 0; i < 65536; i++) + { + union + { + float f; + uint32 i; + } val; + + val.f = (static_cast<float>(i) / 65536.0f) - 0.5f; + source32[i * 4 + 0] = static_cast<uint8>(val.i >> 24); + source32[i * 4 + 1] = static_cast<uint8>(val.i >> 16); + source32[i * 4 + 2] = static_cast<uint8>(val.i >> 8); + source32[i * 4 + 3] = static_cast<uint8>(val.i >> 0); + } + + int16 *truncated16 = static_cast<int16 *>(targetBuf); + ModSample sample; + sample.Initialize(); + sample.nLength = 65536; + sample.uFlags |= CHN_16BIT; + sample.pSample = (LPSTR)(static_cast<int16 *>(targetBuf) + 65536); + CopyAndNormalizeSample<ReadFloat32to16PCMandNormalize<bigEndian32> >(sample, reinterpret_cast<const uint8 *>(source32), sizeof(source32)); + CopySample<ReadFloat32toInt16PCM<bigEndian32> >(truncated16, 65536, 1, source32, 65536 * 4, 1); + + for(size_t i = 0; i < 65536; i++) + { + int16 normValue = reinterpret_cast<const int16 *>(sample.pSample)[i]; + if(abs(normValue - static_cast<int16>(i- 0x8000u)) > 1) + { + VERIFY_EQUAL_NONCONT(true, false); + } + if(abs(truncated16[i] - static_cast<int16>((i - 0x8000u) / 2)) > 1) + { + VERIFY_EQUAL_NONCONT(true, false); + } + } + } + + // Range checks + { + int8 oneSample = 1; + int8 *signed8 = static_cast<int8 *>(targetBuf); + memset(signed8, 0, 4); + CopySample<ReadInt8PCM<0> >(targetBuf, 4, 1, &oneSample, sizeof(oneSample), 1); + VERIFY_EQUAL_NONCONT(signed8[0], 1); + VERIFY_EQUAL_NONCONT(signed8[1], 0); + VERIFY_EQUAL_NONCONT(signed8[2], 0); + VERIFY_EQUAL_NONCONT(signed8[3], 0); + } + + delete[] sourceBuf; + delete[] targetBuf; +} + + }; //Namespace MptTest #else //Case: ENABLE_TESTS is not defined. Modified: trunk/OpenMPT/soundlib/SampleFormatConverters.h =================================================================== --- trunk/OpenMPT/soundlib/SampleFormatConverters.h 2012-05-23 15:27:52 UTC (rev 1279) +++ trunk/OpenMPT/soundlib/SampleFormatConverters.h 2012-05-24 17:30:56 UTC (rev 1280) @@ -233,7 +233,8 @@ { int32 val = sampleConv(sourceBuffer); const double NC = (val < 0) ? 32768.0 : 32767.0; // Normalization Constant - return static_cast<int16>(static_cast<double>(val) / maxVal * NC); + const double roundBias = (val < 0) ? -0.5 : 0.5; + return static_cast<int16>((static_cast<double>(val) / maxVal * NC) + roundBias); } }; @@ -242,26 +243,32 @@ template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex> struct ReadFloat32to16PCMandNormalize : SampleConversionFunctor<float, int16, conversionHasNoState> { - float maxVal; + union + { + float f; + uint32 i; + } maxVal; - ReadFloat32to16PCMandNormalize() : maxVal(0.0f) { } + ReadFloat32to16PCMandNormalize() { maxVal.i = 0; } inline void FindMax(const void *sourceBuffer) { const uint8 *inBuf = static_cast<const uint8 *>(sourceBuffer); - uint32 in32 = inBuf[loLoByteIndex] | (inBuf[loHiByteIndex] << 8) | (inBuf[hiLoByteIndex] << 16) | (inBuf[hiHiByteIndex] << 24); - in32 &= ~0x80000000; // Remove sign for absolute value + uint32 val = inBuf[loLoByteIndex] | (inBuf[loHiByteIndex] << 8) | (inBuf[hiLoByteIndex] << 16) | (inBuf[hiHiByteIndex] << 24); + val &= ~0x80000000; // Remove sign for absolute value - float val = *reinterpret_cast<float *>(&in32); - if(val > maxVal) + // IEEE float values are lexicographically ordered and can be compared when interpreted as integers. + // So we won't bother with loading the float into a floating point register here if we already have it in an integer register. + if(val > maxVal.i) { - maxVal = val; + ASSERT(*reinterpret_cast<float *>(&val) > maxVal.f); + maxVal.i = val; } } bool IsSilent() const { - return (maxVal == 0.0f); + return (maxVal.i == 0); } inline int16 operator() (const void *sourceBuffer) @@ -270,9 +277,9 @@ const uint32 in32 = inBuf[loLoByteIndex] | (inBuf[loHiByteIndex] << 8) | (inBuf[hiLoByteIndex] << 16) | (inBuf[hiHiByteIndex] << 24); const bool negative = (in32 & 0x80000000) != 0; - const float &in = *reinterpret_cast<const float *>(&in32); - int16 result = static_cast<int16>((in / maxVal) * (negative ? 32768.0f : 32767.0f)); - return result; + const float val = (*reinterpret_cast<const float *>(&in32) / maxVal.f) * (negative ? 32768.0f : 32767.0f); + ASSERT(val >= -32768.0f && val <= 32767.0f); + return static_cast<int16>(val); } }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-25 18:04:33
|
Revision: 1282 http://modplug.svn.sourceforge.net/modplug/?rev=1282&view=rev Author: saga-games Date: 2012-05-25 18:04:20 +0000 (Fri, 25 May 2012) Log Message: ----------- [Imp] Correct playback position is now also sent to plugins when jumping around in the order list. [Fix] Song length estimation also takes per-pattern time signatures into account now. [Mod] OpenMPT: Version is now 1.20.01.04 Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Mainfrm.h trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/version.h 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/Ctrl_seq.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -328,13 +328,13 @@ DWORD dwPaused = pSndFile->m_dwSongFlags & (SONG_PAUSED|SONG_STEP|SONG_PATTERNLOOP); - //if (!(dwPaused & SONG_PATTERNLOOP)) // why? // update channel parameters and play time m_pModDoc->SetElapsedTime(m_nScrollPos, 0); pSndFile->m_nCurrentOrder = m_nScrollPos; pSndFile->SetCurrentOrder(m_nScrollPos); pSndFile->m_dwSongFlags |= dwPaused; + if (bIsPlaying) pMainFrm->ResetNotificationBuffer(); } m_pParent->SetCurrentPattern(n); Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -2449,13 +2449,6 @@ return CSoundFile::GetSampleRate(); } -long CMainFrame::GetTotalSampleCount() -//------------------------------------ -{ - if (GetModPlaying()) - return GetModPlaying()->GetSoundFile()->m_lTotalSampleCount; - return 0; -} double CMainFrame::GetApproxBPM() //------------------------------- Modified: trunk/OpenMPT/mptrack/Mainfrm.h =================================================================== --- trunk/OpenMPT/mptrack/Mainfrm.h 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/mptrack/Mainfrm.h 2012-05-25 18:04:20 UTC (rev 1282) @@ -531,7 +531,6 @@ CWnd *m_pNoteMapHasFocus; //rewbs.customKeys CWnd* m_pOrderlistHasFocus; long GetSampleRate(); //rewbs.VSTTimeInfo - long GetTotalSampleCount(); //rewbs.VSTTimeInfo double GetApproxBPM(); //rewbs.VSTTimeInfo void ThreadSafeSetModified(CModDoc* modified) {m_pJustModifiedDoc=modified;} Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -1898,7 +1898,7 @@ //User has sent play song command: set loop pattern checkbox to false. pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, 0); } - + bool isPlaying = (pMainFrm->GetModPlaying() == this); if ((isPlaying) && (!(m_SndFile.m_dwSongFlags & (SONG_PAUSED|SONG_STEP/*|SONG_PATTERNLOOP*/)))) { @@ -1908,11 +1908,14 @@ CriticalSection cs; - for (UINT i=m_SndFile.m_nChannels; i<MAX_CHANNELS; i++) if (!m_SndFile.Chn[i].nMasterChn) + for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++) if (!m_SndFile.Chn[i].nMasterChn) { m_SndFile.Chn[i].dwFlags |= (CHN_NOTEFADE|CHN_KEYOFF); if (!isPlaying) m_SndFile.Chn[i].nLength = 0; } + + m_SndFile.m_bPositionChanged = true; + if (isPlaying) { m_SndFile.StopAllVsti(); @@ -2005,9 +2008,14 @@ m_SndFile.SetCurrentPos(0); m_SndFile.visitedSongRows.Initialize(true); pMainFrm->ResetElapsedTime(); + m_SndFile.m_lTotalSampleCount = 0; + m_SndFile.m_bPositionChanged = true; CriticalSection cs; + + m_SndFile.m_bPositionChanged = true; m_SndFile.ResumePlugins(); + cs.Leave(); pMainFrm->PlayMod(this, m_hWndFollow, m_dwNotifyType); @@ -2285,7 +2293,7 @@ //User has sent play pattern command: set loop pattern checkbox to true. pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, 1); } - + CSoundFile *pSndFile = GetSoundFile(); ROWINDEX nRow; @@ -2299,11 +2307,8 @@ CriticalSection cs; - // set playback timer in the status bar (and update channel status) - SetElapsedTime(nOrd, 0); - // Cut instruments/samples - for (UINT i=0; i<MAX_CHANNELS; i++) + for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) { pSndFile->Chn[i].nPatternLoopCount = 0; pSndFile->Chn[i].nPatternLoop = 0; @@ -2314,7 +2319,10 @@ pSndFile->m_dwSongFlags &= ~(SONG_PAUSED|SONG_STEP); pSndFile->LoopPattern(nPat); pSndFile->m_nNextRow = 0; - //rewbs.vstCompliance + + // set playback timer in the status bar (and update channel status) + SetElapsedTime(nOrd, 0); + if (pModPlaying == this) { pSndFile->StopAllVsti(); @@ -2322,7 +2330,7 @@ { pSndFile->ResumePlugins(); } - //end rewbs.vstCompliance + cs.Leave(); if (pModPlaying != this) @@ -2346,7 +2354,7 @@ //User has sent play pattern command: set loop pattern checkbox to true. pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, 1); } - + CSoundFile *pSndFile = GetSoundFile(); ROWINDEX nRow; @@ -2360,11 +2368,8 @@ CriticalSection cs; - // set playback timer in the status bar (and update channel status) - SetElapsedTime(nOrd, nRow); - // Cut instruments/samples - for (UINT i=pSndFile->m_nChannels; i<MAX_CHANNELS; i++) + for(CHANNELINDEX i = pSndFile->GetNumChannels(); i < MAX_CHANNELS; i++) { pSndFile->Chn[i].dwFlags |= CHN_NOTEFADE | CHN_KEYOFF; } @@ -2372,7 +2377,10 @@ pSndFile->m_dwSongFlags &= ~(SONG_PAUSED|SONG_STEP); pSndFile->LoopPattern(nPat); pSndFile->m_nNextRow = nRow; - //rewbs.VSTCompliance + + // set playback timer in the status bar (and update channel status) + SetElapsedTime(nOrd, nRow); + if (pModPlaying == this) { pSndFile->StopAllVsti(); @@ -2380,7 +2388,7 @@ { pSndFile->ResumePlugins(); } - //end rewbs.VSTCompliance + cs.Leave(); if (pModPlaying != this) @@ -2405,7 +2413,7 @@ //User has sent play song command: set loop pattern checkbox to false. pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, 0); } - + CSoundFile *pSndFile = GetSoundFile(); ROWINDEX nRow; @@ -2418,12 +2426,8 @@ CModDoc *pModPlaying = pMainFrm->GetModPlaying(); CriticalSection cs; - - // set playback timer in the status bar (and update channel status) - SetElapsedTime(nOrd, nRow); - // Cut instruments/samples - for (UINT i=pSndFile->m_nChannels; i<MAX_CHANNELS; i++) + for(CHANNELINDEX i = pSndFile->GetNumChannels(); i < MAX_CHANNELS; i++) { pSndFile->Chn[i].dwFlags |= CHN_NOTEFADE | CHN_KEYOFF; } @@ -2434,13 +2438,18 @@ else pSndFile->LoopPattern(nPat); pSndFile->m_nNextRow = nRow; - //end rewbs.VSTCompliance - if (pModPlaying == this) { - pSndFile->StopAllVsti(); - } else { + + // set playback timer in the status bar (and update channel status) + SetElapsedTime(nOrd, nRow); + + if (pModPlaying == this) + { + pSndFile->StopAllVsti(); + } else + { pSndFile->ResumePlugins(); } - //rewbs.VSTCompliance + cs.Leave(); if (pModPlaying != this) @@ -2689,12 +2698,12 @@ void CModDoc::SetElapsedTime(ORDERINDEX nOrd, ROWINDEX nRow) //---------------------------------------------------------- { + const double dPatternPlaytime = m_SndFile.GetPlaybackTimeAt(nOrd, nRow, true); CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); - if(pMainFrm == NULL) - return; - - const double dPatternPlaytime = m_SndFile.GetPlaybackTimeAt(nOrd, nRow, true); - pMainFrm->SetElapsedTime((DWORD) (max(0, dPatternPlaytime) * 1000)); + if(pMainFrm != nullptr) + { + pMainFrm->SetElapsedTime(static_cast<DWORD>(Util::Max(0.0, dPatternPlaytime) * 1000.0)); + } } Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -715,15 +715,14 @@ MemsetZero(timeInfo); timeInfo.sampleRate = CMainFrame::GetMainFrame()->GetSampleRate(); - if (pVstPlugin) + CSoundFile *pSndFile; + if(pVstPlugin && (pSndFile = pVstPlugin->GetSoundFile()) != nullptr) { - CSoundFile* pSndFile = pVstPlugin->GetSoundFile(); - - if (pVstPlugin->IsSongPlaying()) + if(pVstPlugin->IsSongPlaying()) { timeInfo.flags |= kVstTransportPlaying; - timeInfo.samplePos = CMainFrame::GetMainFrame()->GetTotalSampleCount(); - if (timeInfo.samplePos == 0) //samplePos=0 means we just started playing + timeInfo.samplePos = pSndFile->GetTotalSampleCount(); + if(pSndFile->HasPositionChanged()) { timeInfo.flags |= kVstTransportChanged; } @@ -732,12 +731,12 @@ timeInfo.flags |= kVstTransportChanged; //just stopped. timeInfo.samplePos = 0; } - if ((value & kVstNanosValid)) + if((value & kVstNanosValid)) { timeInfo.flags |= kVstNanosValid; timeInfo.nanoSeconds = timeGetTime() * 1000000; } - if ((value & kVstPpqPosValid) && pSndFile) + if((value & kVstPpqPosValid)) { timeInfo.flags |= kVstPpqPosValid; if (timeInfo.flags & kVstTransportPlaying) @@ -748,7 +747,7 @@ timeInfo.ppqPos = 0; } } - if ((value & kVstTempoValid) && pSndFile) + if ((value & kVstTempoValid)) { timeInfo.tempo = pSndFile->GetCurrentBPM(); if (timeInfo.tempo) @@ -756,7 +755,7 @@ timeInfo.flags |= kVstTempoValid; } } - if ((value & kVstTimeSigValid) && pSndFile) + if ((value & kVstTimeSigValid)) { timeInfo.flags |= kVstTimeSigValid; @@ -2284,7 +2283,7 @@ VSTInstrChannel &channel = m_MidiCh[mc]; MidiPitchBend(mc, MIDIEvents::pitchBendCentre); // centre pitch bend - MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllControllersOff, mc, 0)); // reset all controllers + 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 Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/mptrack/version.h 2012-05-25 18:04:20 UTC (rev 1282) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 03 +#define VER_MINORMINOR 04 //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-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -161,6 +161,8 @@ // 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); + samplecount_t renderedSamples = 0; + for (;;) { UINT rowDelay = 0, tickDelay = 0; @@ -528,8 +530,17 @@ nNextPatStartRow = 0; } - // XXX this does not take per-pattern time signatures into consideration! - memory.elapsedTime += GetRowDuration(memory.musicTempo, memory.musicSpeed, (memory.musicSpeed + tickDelay) * max(rowDelay, 1)); + ROWINDEX rowsPerBeat = m_nDefaultRowsPerBeat; + if(Patterns[nPattern].GetOverrideSignature()) + { + rowsPerBeat = Patterns[nPattern].GetRowsPerBeat(); + } + + const UINT tickDuration = GetTickDuration(memory.musicTempo, memory.musicSpeed, rowsPerBeat); + const UINT rowDuration = tickDuration * (memory.musicSpeed + tickDelay) * max(rowDelay, 1); + + memory.elapsedTime += static_cast<double>(rowDuration) / static_cast<double>(gdwMixingFreq); + renderedSamples += rowDuration; } if(retval.targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) @@ -537,15 +548,17 @@ retval.lastOrder = nCurrentOrder; retval.lastRow = nRow; } - retval.duration = memory.elapsedTime / 1000.0; + retval.duration = memory.elapsedTime; // Store final variables - if ((adjustMode & eAdjust)) + if((adjustMode & eAdjust)) { - if (retval.targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) + if(retval.targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) { // Target found, or there is no target (i.e. play whole song)... m_nGlobalVolume = memory.glbVol; + m_lTotalSampleCount = renderedSamples; + m_bPositionChanged = true; if(IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2)) { //IT compatibility 16. Global volume slide params are stored per channel (FT2/IT) @@ -559,10 +572,10 @@ } m_nMusicSpeed = memory.musicSpeed; m_nMusicTempo = memory.musicTempo; - for (CHANNELINDEX n = 0; n < GetNumChannels(); n++) + for(CHANNELINDEX n = 0; n < GetNumChannels(); n++) { Chn[n].nGlobalVol = memory.chnVols[n]; - if (memory.notes[n] != NOTE_NONE) + if(memory.notes[n] != NOTE_NONE) { Chn[n].nNewNote = memory.notes[n]; if(ModCommand::IsNote(memory.notes[n])) @@ -570,10 +583,10 @@ Chn[n].nLastNote = memory.notes[n]; } } - if (memory.instr[n]) Chn[n].nNewIns = memory.instr[n]; - if (memory.vols[n] != 0xFF) + if(memory.instr[n]) Chn[n].nNewIns = memory.instr[n]; + if(memory.vols[n] != 0xFF) { - if (memory.vols[n] > 64) memory.vols[n] = 64; + if(memory.vols[n] > 64) memory.vols[n] = 64; Chn[n].nVolume = memory.vols[n] * 4; } } Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -486,7 +486,8 @@ MemsetZero(m_MixPlugins); Order.Init(); Patterns.ClearPatterns(); - m_lTotalSampleCount=0; + m_lTotalSampleCount = 0; + m_bPositionChanged = true; m_pConfig = new CSoundFilePlayConfig(); m_pTuningsTuneSpecific = new CTuningCollection("Tune specific tunings"); @@ -1153,7 +1154,6 @@ pPlugin->Suspend(); } } - m_lTotalSampleCount=0; } void CSoundFile::ResumePlugins() @@ -1171,8 +1171,6 @@ pPlugin->Resume(); } } - m_lTotalSampleCount=GetSampleOffset(); - } @@ -1190,7 +1188,6 @@ pPlugin->HardAllNotesOff(); } } - m_lTotalSampleCount = GetSampleOffset(); } @@ -1768,16 +1765,6 @@ } -long CSoundFile::GetSampleOffset() -//-------------------------------- -{ - //TODO: This is where we could inform patterns of the exact song position when playback starts. - //order: m_nNextPattern - //long ticksFromStartOfPattern = m_nRow*m_nMusicSpeed; - //return ticksFromStartOfPattern*m_nSamplesPerTick; - return 0; -} - string CSoundFile::GetNoteName(const CTuning::NOTEINDEXTYPE& note, const INSTRUMENTINDEX inst) const //-------------------------------------------------------------------------------------------------- { @@ -1899,30 +1886,60 @@ } +// Get length of a tick in sample, with tick-to-tick tempo correction in modern tempo mode. +UINT CSoundFile::GetTickDuration(UINT tempo, UINT speed, ROWINDEX rowsPerBeat) +//---------------------------------------------------------------------------- +{ + switch(m_nTempoMode) + { + case tempo_mode_classic: + default: + return (gdwMixingFreq * 5 * m_nTempoFactor) / (tempo << 8); + + case tempo_mode_alternative: + return gdwMixingFreq / tempo; + + case tempo_mode_modern: + { + double accurateBufferCount = static_cast<double>(gdwMixingFreq) * (60.0 / static_cast<double>(tempo) / (static_cast<double>(speed * rowsPerBeat))); + UINT bufferCount = static_cast<int>(accurateBufferCount); + m_dBufferDiff += accurateBufferCount - bufferCount; + + //tick-to-tick tempo correction: + if(m_dBufferDiff >= 1) + { + bufferCount++; + m_dBufferDiff--; + } else if(m_dBufferDiff <= -1) + { + bufferCount--; + m_dBufferDiff++; + } + ASSERT(abs(m_dBufferDiff) < 1); + return bufferCount; + } + } +} + + // Get the duration of a row in milliseconds, based on the current rows per beat and given speed and tempo settings. -// "speedIncludingPatternDelays" is the total row length, including the ticks from Row Delay effects. -// It is required because modern tempo mode normally doesn't consider "speed", so "speedIncludingPatternDelays" is -// used as a ratio. -double CSoundFile::GetRowDuration(UINT tempo, UINT speed, UINT speedIncludingPatternDelays) const -//----------------------------------------------------------------------------------------------- +double CSoundFile::GetRowDuration(UINT tempo, UINT speed) const +//------------------------------------------------------------- { - speedIncludingPatternDelays = Util::Max(speedIncludingPatternDelays, speed); - switch(m_nTempoMode) { case tempo_mode_classic: default: - return static_cast<double>(2500 * speedIncludingPatternDelays) / static_cast<double>(tempo); + return static_cast<double>(2500 * speed) / static_cast<double>(tempo); case tempo_mode_modern: { // If there are any row delay effects, the row length factor compensates for those. - const double rowLength = static_cast<double>(speedIncludingPatternDelays) / static_cast<double>(speed); - return 60000.0 * rowLength / static_cast<double>(tempo) / static_cast<double>(m_nCurrentRowsPerBeat); + return 60000.0 / static_cast<double>(tempo) / static_cast<double>(m_nCurrentRowsPerBeat); } case tempo_mode_alternative: - return static_cast<double>(1000 * speedIncludingPatternDelays) / static_cast<double>(tempo); + return static_cast<double>(1000 * speed) / static_cast<double>(tempo); } } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-05-25 18:04:20 UTC (rev 1282) @@ -243,6 +243,7 @@ static PMIXPLUGINCREATEPROC gpMixPluginCreateProc; static uint8 s_DefaultPlugVolumeHandling; + typedef uint32 samplecount_t; // Number of rendered samples public: // for Editing CModDoc *m_pModDoc; // Can be a null pointer for example when previewing samples from the treeview. @@ -253,11 +254,13 @@ UINT m_nDefaultSpeed, m_nDefaultTempo, m_nDefaultGlobalVolume; DWORD m_dwSongFlags; // Song flags SONG_XXXX bool m_bIsRendering; - UINT m_nMixChannels, m_nMixStat, m_nBufferCount; + UINT m_nMixChannels, m_nMixStat; + samplecount_t m_nBufferCount; double m_dBufferDiff; UINT m_nTickCount; UINT m_nPatternDelay, m_nFrameDelay; // m_nPatternDelay = pattern delay (rows), m_nFrameDelay = fine pattern delay (ticks) - ULONG m_lTotalSampleCount; // rewbs.VSTTimeInfo + samplecount_t m_lTotalSampleCount; // rewbs.VSTTimeInfo + bool m_bPositionChanged; // Report to plugins that we jumped around in the module UINT m_nSamplesPerTick; // rewbs.betterBPM ROWINDEX m_nDefaultRowsPerBeat, m_nDefaultRowsPerMeasure; // default rows per beat and measure for this module // rewbs.betterBPM ROWINDEX m_nCurrentRowsPerBeat, m_nCurrentRowsPerMeasure; // current rows per beat and measure for this module @@ -319,8 +322,14 @@ bool TypeIsS3M_IT_MPT() const { return (m_nType & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) != 0; } bool TypeIsXM_MOD() const { return (m_nType & (MOD_TYPE_XM | MOD_TYPE_MOD)) != 0; } bool TypeIsMOD_S3M() const { return (m_nType & (MOD_TYPE_MOD | MOD_TYPE_S3M)) != 0; } - CModDoc* GetpModDoc() const { return m_pModDoc; } + // Get parent CModDoc. Can be nullptr if previewing from tree view, and is always nullptr if we're not actually compiling OpenMPT. +#ifdef MODPLUG_TRACKER + CModDoc *GetpModDoc() const { return m_pModDoc; } +#else + void *GetpModDoc() const { return nullptr; } +#endif // MODPLUG_TRACKER + void SetMasterVolume(UINT vol, bool adjustAGC = false); UINT GetMasterVolume() const { return m_nMasterVolume; } @@ -354,7 +363,8 @@ DWORD GetSongTime() { return static_cast<DWORD>(GetLength(eNoAdjust).duration + 0.5); } void RecalculateSamplesPerTick(); - double GetRowDuration(UINT tempo, UINT speed, UINT speedIncludingPatternDelays = 0) const; + double GetRowDuration(UINT tempo, UINT speed) const; + UINT GetTickDuration(UINT tempo, UINT speed, ROWINDEX rowsPerBeat); // A repeat count value of -1 means infinite loop void SetRepeatCount(int n) { m_nRepeatCount = n; } @@ -448,6 +458,8 @@ BOOL FadeSong(UINT msec); BOOL GlobalFadeSong(UINT msec); void ProcessPlugins(UINT nCount); + size_t GetTotalSampleCount() const { return m_lTotalSampleCount; } + bool HasPositionChanged() { bool b = m_bPositionChanged; m_bPositionChanged = false; return b; } public: // Mixer Config @@ -662,7 +674,7 @@ // System-Dependant functions public: static LPSTR AllocateSample(UINT nbytes); - static void FreeSample(LPVOID p); + static void FreeSample(void *p); // WAV export static UINT Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lmax24, DWORD dwByteInc); @@ -722,7 +734,6 @@ PLUGINDEX __cdecl GetActiveInstrumentPlugin(CHANNELINDEX, PluginMutePriority respectMutes) const; void HandlePatternTransitionEvents(); - long GetSampleOffset(); public: PLUGINDEX GetBestPlugin(CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const; Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2012-05-25 17:04:28 UTC (rev 1281) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2012-05-25 18:04:20 UTC (rev 1282) @@ -250,11 +250,11 @@ BOOL CSoundFile::FadeSong(UINT msec) //---------------------------------- { - LONG nsamples = _muldiv(msec, gdwMixingFreq, 1000); + samplecount_t nsamples = _muldiv(msec, gdwMixingFreq, 1000); if (nsamples <= 0) return FALSE; if (nsamples > 0x100000) nsamples = 0x100000; m_nBufferCount = nsamples; - LONG nRampLength = m_nBufferCount; + samplecount_t nRampLength = m_nBufferCount; // Ramp everything down for (UINT noff=0; noff < m_nMixChannels; noff++) { @@ -289,7 +289,9 @@ { LPBYTE lpBuffer = (LPBYTE)lpDestBuffer; LPCONVERTPROC pCvt = X86_Convert32To8; - UINT lRead, lMax, lSampleSize, lCount, lSampleCount, nStat=0; + samplecount_t lMax, lCount, lSampleCount; + size_t lSampleSize; + UINT nStat = 0; UINT nMaxPlugins; nMaxPlugins = MAX_MIXPLUGINS; @@ -305,7 +307,7 @@ lMax = cbBuffer / lSampleSize; if ((!lMax) || (!lpBuffer) || (!m_nChannels)) return 0; - lRead = lMax; + samplecount_t lRead = lMax; if (m_dwSongFlags & SONG_ENDREACHED) goto MixDone; @@ -1847,44 +1849,12 @@ //////////////////////////////////////////////////////////////////////////////////// if (!m_nMusicTempo) return FALSE; - switch(m_nTempoMode) - { + m_nSamplesPerTick = m_nBufferCount = GetTickDuration(m_nMusicTempo, m_nMusicSpeed, m_nCurrentRowsPerBeat); - case tempo_mode_alternative: - m_nBufferCount = gdwMixingFreq / m_nMusicTempo; - break; - - case tempo_mode_modern: - { - double accurateBufferCount = (double)gdwMixingFreq * (60.0 / (double)m_nMusicTempo / ((double)m_nMusicSpeed * (double)m_nCurrentRowsPerBeat)); - m_nBufferCount = static_cast<int>(accurateBufferCount); - m_dBufferDiff += accurateBufferCount-m_nBufferCount; - //tick-to-tick tempo correction: - if (m_dBufferDiff >= 1) - { - m_nBufferCount++; - m_dBufferDiff--; - } else if (m_dBufferDiff <= -1) - { - m_nBufferCount--; - m_dBufferDiff++; - } - ASSERT(abs(m_dBufferDiff) < 1); - break; - } - - case tempo_mode_classic: - default: - m_nBufferCount = (gdwMixingFreq * 5 * m_nTempoFactor) / (m_nMusicTempo << 8); - } - - m_nSamplesPerTick = m_nBufferCount; //rewbs.flu - - // Master Volume + Pre-Amplification / Attenuation setup DWORD nMasterVol; { - int nchn32 = CLAMP(m_nChannels, 1, 31); + CHANNELINDEX nchn32 = Clamp(m_nChannels, CHANNELINDEX(1), CHANNELINDEX(31)); DWORD mastervol; @@ -1894,7 +1864,7 @@ if (realmastervol > 0x80) { //Attenuate global pre-amp depending on num channels - realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32+4)) / 16; + realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32 + 4)) / 16; } mastervol = (realmastervol * (m_nSamplePreAmp)) >> 6; } else @@ -1910,7 +1880,7 @@ if (m_pConfig->getUseGlobalPreAmp()) { - UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32>>1] : PreAmpTable[nchn32>>1]; + UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32 >> 1] : PreAmpTable[nchn32 >> 1]; if(attenuation < 1) attenuation = 1; nMasterVol = (mastervol << 7) / attenuation; } else @@ -2120,7 +2090,7 @@ } // Applying Pitch/Tempo lock. - if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT) && pIns && pIns->wPitchToTempoLock) + if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT) && pIns && pIns->wPitchToTempoLock) { freq = _muldivr(freq, m_nMusicTempo, pIns->wPitchToTempoLock); } @@ -2456,11 +2426,11 @@ //If new note, determine notevelocity to use. if(note != NOTE_NONE) { - UINT velocity = 4 * defaultVolume; + uint16 velocity = static_cast<uint16>(4 * defaultVolume); switch(pIns->nPluginVelocityHandling) { case PLUGIN_VELOCITYHANDLING_CHANNEL: - velocity = pChn->nVolume; + velocity = static_cast<uint16>(pChn->nVolume); break; } @@ -2486,7 +2456,7 @@ case PLUGIN_VOLUMEHANDLING_MIDI: if(hasVolCommand) pPlugin->MidiCC(GetBestMidiChannel(nChn), MIDIEvents::MIDICC_Volume_Coarse, min(127, 2 * vol), nChn); - else pPlugin->MidiCC(GetBestMidiChannel(nChn), MIDIEvents::MIDICC_Volume_Coarse, min(127, 2 * defaultVolume), nChn); + else pPlugin->MidiCC(GetBestMidiChannel(nChn), MIDIEvents::MIDICC_Volume_Coarse, static_cast<uint8>(min(127, 2 * defaultVolume)), nChn); break; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <man...@us...> - 2012-05-25 22:37:26
|
Revision: 1284 http://modplug.svn.sourceforge.net/modplug/?rev=1284&view=rev Author: manxorist Date: 2012-05-25 22:37:20 +0000 (Fri, 25 May 2012) Log Message: ----------- Add svn:ignore property for ASIO and VST SDK files and any VisualStudio generated files. Property Changed: ---------------- trunk/OpenMPT/include/ASIOSDK2/ trunk/OpenMPT/include/vstsdk2.4/ trunk/OpenMPT/mptrack/ trunk/OpenMPT/mptrack/bin/ trunk/OpenMPT/soundtouch/ trunk/OpenMPT/ungzip/ trunk/OpenMPT/unlha/ trunk/OpenMPT/unrar/ trunk/OpenMPT/unzip/ trunk/OpenMPT/xsoundlib/ trunk/OpenMPT/zlib/contrib/vstudio/vc10/ Property changes on: trunk/OpenMPT/include/ASIOSDK2 ___________________________________________________________________ Added: svn:ignore + * Property changes on: trunk/OpenMPT/include/vstsdk2.4 ___________________________________________________________________ Added: svn:ignore + * Property changes on: trunk/OpenMPT/mptrack ___________________________________________________________________ Added: svn:ignore + Debug *.user *.suo *.sdf *.opensdf Release Property changes on: trunk/OpenMPT/mptrack/bin ___________________________________________________________________ Added: svn:ignore + * Property changes on: trunk/OpenMPT/soundtouch ___________________________________________________________________ Added: svn:ignore + Debug Release *.user Property changes on: trunk/OpenMPT/ungzip ___________________________________________________________________ Added: svn:ignore + Debug Release *.user Property changes on: trunk/OpenMPT/unlha ___________________________________________________________________ Added: svn:ignore + Debug bin Release *.user Property changes on: trunk/OpenMPT/unrar ___________________________________________________________________ Added: svn:ignore + bin Debug Release *.user Property changes on: trunk/OpenMPT/unzip ___________________________________________________________________ Added: svn:ignore + bin Debug Release *.user Property changes on: trunk/OpenMPT/xsoundlib ___________________________________________________________________ Added: svn:ignore + Debug Release *.user Property changes on: trunk/OpenMPT/zlib/contrib/vstudio/vc10 ___________________________________________________________________ Added: svn:ignore + x86 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-27 15:53:06
|
Revision: 1287 http://modplug.svn.sourceforge.net/modplug/?rev=1287&view=rev Author: saga-games Date: 2012-05-27 15:52:58 +0000 (Sun, 27 May 2012) Log Message: ----------- [Ref] Rewrote WAV loaders to share more code. The actual WAV loading is now done in WAVTools.cpp. Modified Paths: -------------- trunk/OpenMPT/common/StringFixer.h trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/ChunkReader.h trunk/OpenMPT/soundlib/Dlsbank.cpp trunk/OpenMPT/soundlib/Load_umx.cpp trunk/OpenMPT/soundlib/Load_wav.cpp trunk/OpenMPT/soundlib/Loaders.h trunk/OpenMPT/soundlib/ModSample.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Added Paths: ----------- trunk/OpenMPT/soundlib/WAVTools.cpp trunk/OpenMPT/soundlib/WAVTools.h Modified: trunk/OpenMPT/common/StringFixer.h =================================================================== --- trunk/OpenMPT/common/StringFixer.h 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/common/StringFixer.h 2012-05-27 15:52:58 UTC (rev 1287) @@ -83,7 +83,7 @@ //---------------------------------------------------------------------------------------- { STATIC_ASSERT(destSize > 0); - ASSERT(srcSize > 0); + //ASSERT(srcSize > 0); const size_t maxSize = min(destSize, srcSize); char *dst = destBuffer; Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-05-27 15:52:58 UTC (rev 1287) @@ -612,10 +612,6 @@ RelativePath="..\soundlib\WindowedFIR.cpp" > </File> - <File - RelativePath="..\soundlib\XMTools.cpp" - > - </File> <Filter Name="PatternRandomizer" > @@ -1246,10 +1242,6 @@ RelativePath="..\soundlib\WindowedFIR.h" > </File> - <File - RelativePath=".\soundlib\XMTools.h" - > - </File> <Filter Name="tuning" > @@ -1486,6 +1478,22 @@ RelativePath="..\soundlib\Loaders.h" > </File> + <File + RelativePath="..\soundlib\WAVTools.cpp" + > + </File> + <File + RelativePath="..\soundlib\WAVTools.h" + > + </File> + <File + RelativePath="..\soundlib\XMTools.cpp" + > + </File> + <File + RelativePath="..\soundlib\XMTools.h" + > + </File> </Filter> <File RelativePath=".\res\built-inTunings.tc" Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-05-27 15:52:58 UTC (rev 1287) @@ -179,6 +179,7 @@ <ClCompile Include="..\soundlib\RowVisitor.cpp" /> <ClCompile Include="..\soundlib\SampleFormats.cpp" /> <ClCompile Include="..\soundlib\SampleIO.cpp" /> + <ClCompile Include="..\soundlib\WAVTools.cpp" /> <ClCompile Include="..\soundlib\XMTools.cpp" /> <ClCompile Include="AbstractVstEditor.cpp" /> <ClCompile Include="ACMConvert.cpp" /> @@ -349,6 +350,7 @@ <ClInclude Include="..\soundlib\RowVisitor.h" /> <ClInclude Include="..\soundlib\SampleFormatConverters.h" /> <ClInclude Include="..\soundlib\SampleIO.h" /> + <ClInclude Include="..\soundlib\WAVTools.h" /> <ClInclude Include="..\soundlib\XMTools.h" /> <ClInclude Include="ACMConvert.h" /> <ClInclude Include="Autotune.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-05-27 15:52:58 UTC (rev 1287) @@ -463,6 +463,9 @@ <ClCompile Include="..\soundlib\SampleFormats.cpp"> <Filter>Module Loaders</Filter> </ClCompile> + <ClCompile Include="..\soundlib\WAVTools.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -825,6 +828,9 @@ <ClInclude Include="..\soundlib\SampleFormatConverters.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\soundlib\WAVTools.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/soundlib/ChunkReader.h =================================================================== --- trunk/OpenMPT/soundlib/ChunkReader.h 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/ChunkReader.h 2012-05-27 15:52:58 UTC (rev 1287) @@ -29,24 +29,21 @@ //================= { private: - const T chunkHeader; - ChunkReader chunkData; + T chunkHeader; + FileReader chunkData; public: ChunkListItem(const T &header, const FileReader &data) : chunkHeader(header), chunkData(data) { } - // VC2008 needs operator=, VC2010 doesn't... - ChunkListItem<T>& operator= (const ChunkListItem<T> &other) + + ChunkListItem<T> &operator= (const ChunkListItem<T> &other) { - return MemCopy(*this, other); + chunkHeader = other.chunkHeader; + chunkData = other.chunkData; + return *this; } const T &GetHeader() const { return chunkHeader; } - FileReader &GetData() { return chunkData; } - - bool operator== (const ChunkListItem<T> &other) - { - return (GetHeader().GetID() == other.GetHeader().GetID()); - } + const FileReader &GetData() const { return chunkData; } }; template<typename T> @@ -57,8 +54,7 @@ public: // Check if the list contains a given chunk. - template<typename IdType> - bool ChunkExists(IdType id) const + bool ChunkExists(typename T::id_type id) const { for(const_iterator iter = begin(); iter != end(); iter++) { @@ -71,25 +67,23 @@ } // Retrieve the first chunk with a given ID. - template<typename IdType> - FileReader GetChunk(IdType id) + FileReader GetChunk(typename T::id_type id) const { - for(iterator iter = begin(); iter != end(); iter++) + for(const_iterator iter = begin(); iter != end(); iter++) { if(iter->GetHeader().GetID() == id) { return iter->GetData(); } } - return FileReader(nullptr, 0); + return FileReader(); } // Retrieve all chunks with a given ID. - template<typename IdType> - std::vector<FileReader> GetAllChunks(IdType id) + std::vector<FileReader> GetAllChunks(typename T::id_type id) const { std::vector<FileReader> result; - for(iterator iter = begin(); iter != end(); iter++) + for(const_iterator iter = begin(); iter != end(); iter++) { if(iter->GetHeader().GetID() == id) { @@ -98,11 +92,13 @@ } return result; } - }; // Read a series of "T" chunks until the end of file is reached. + // T is required to have the methods GetID() and GetLength(), as well as an id_type typedef. + // GetLength() should return the chunk size in bytes, and GetID() the chunk ID. + // id_type must reflect the type that is returned by GetID(). template<typename T> ChunkList<T> ReadChunks(size_t padding) { Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp =================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp 2012-05-27 15:52:58 UTC (rev 1287) @@ -1469,11 +1469,11 @@ BOOL CDLSBank::ExtractSample(CSoundFile *pSndFile, SAMPLEINDEX nSample, UINT nIns, UINT nRgn, int transpose) -//--------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------- { DLSINSTRUMENT *pDlsIns; LPBYTE pWaveForm = NULL; - DWORD dwLen = 0, dwWSMPOffset = 0; + DWORD dwLen = 0; BOOL bOk, bWaveForm; if ((!m_pInstruments) || (nIns >= m_nInstruments) || (!pSndFile)) return FALSE; @@ -1482,6 +1482,8 @@ if (!ExtractWaveForm(nIns, nRgn, &pWaveForm, &dwLen)) return FALSE; if ((!pWaveForm) || (dwLen < 16)) return FALSE; bOk = FALSE; + + FileReader wsmpChunk; if (m_nType & SOUNDBANK_TYPE_SF2) { pSndFile->DestroySample(nSample); @@ -1512,7 +1514,8 @@ bWaveForm = (sample.pSample) ? TRUE : FALSE; } else { - bWaveForm = pSndFile->ReadWAVSample(nSample, pWaveForm, dwLen, &dwWSMPOffset); + FileReader file(reinterpret_cast<const char *>(pWaveForm), dwLen); + bWaveForm = pSndFile->ReadWAVSample(nSample, file, &wsmpChunk); } if (bWaveForm) { @@ -1545,21 +1548,24 @@ UINT usUnityNote = pRgn->uUnityNote; int sFineTune = pRgn->sFineTune; int lVolume = pRgn->usVolume; - if ((dwWSMPOffset) && (!(pRgn->fuOptions & DLSREGION_OVERRIDEWSMP))) + + WSMPCHUNK wsmp; + if(!(pRgn->fuOptions & DLSREGION_OVERRIDEWSMP) && wsmpChunk.ReadStructPartial(wsmp)) { - WSMPCHUNK *p = (WSMPCHUNK *)(pWaveForm + dwWSMPOffset); - usUnityNote = p->usUnityNote; - sFineTune = p->sFineTune; - lVolume = DLS32BitRelativeGainToLinear(p->lAttenuation) / 256; - if (p->cSampleLoops) + usUnityNote = wsmp.usUnityNote; + sFineTune = wsmp.sFineTune; + lVolume = DLS32BitRelativeGainToLinear(wsmp.lAttenuation) / 256; + if(wsmp.cSampleLoops) { - WSMPSAMPLELOOP *ploop = (WSMPSAMPLELOOP *)(pWaveForm+dwWSMPOffset+8+p->cbSize); - if (ploop->ulLoopLength > 3) + WSMPSAMPLELOOP loop; + wsmpChunk.Skip(8 + wsmp.cbSize); + wsmpChunk.Read(loop); + if(loop.ulLoopLength > 3) { sample.uFlags |= CHN_LOOP; - //if (ploop->ulLoopType) sample.uFlags |= CHN_PINGPONGLOOP; - sample.nLoopStart = ploop->ulLoopStart; - sample.nLoopEnd = ploop->ulLoopStart + ploop->ulLoopLength; + //if (loop.ulLoopType) sample.uFlags |= CHN_PINGPONGLOOP; + sample.nLoopStart = loop.ulLoopStart; + sample.nLoopEnd = loop.ulLoopStart + loop.ulLoopLength; } } } else Modified: trunk/OpenMPT/soundlib/Load_umx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_umx.cpp 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/Load_umx.cpp 2012-05-27 15:52:58 UTC (rev 1287) @@ -274,7 +274,7 @@ if(ReadIT(data, fileChunk.GetLength()) || ReadXM(data, fileChunk.GetLength()) || ReadS3M(fileChunk) - || ReadWav(data, fileChunk.GetLength()) + || ReadWav(fileChunk) || ReadMod(fileChunk)) { return true; Modified: trunk/OpenMPT/soundlib/Load_wav.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_wav.cpp 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/Load_wav.cpp 2012-05-27 15:52:58 UTC (rev 1287) @@ -11,12 +11,9 @@ #include "stdafx.h" #include "Loaders.h" -#include "Wav.h" +#include "WAVTools.h" #include "SampleFormatConverters.h" -#ifndef WAVE_FORMAT_EXTENSIBLE -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif ///////////////////////////////////////////////////////////// // WAV file support @@ -43,126 +40,136 @@ } -bool CSoundFile::ReadWav(const BYTE *lpStream, const DWORD dwMemLength) -//--------------------------------------------------------------------- +bool CSoundFile::ReadWav(FileReader &file) +//---------------------------------------- { - DWORD dwMemPos = 0; - WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream; - WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER)); - if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return false; - if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE) - || (pfmt->id_fmt != IFFID_fmt)) return false; - dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen; - if ((dwMemPos + 8 >= dwMemLength) - || ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE) && (pfmt->format != WAVE_FORMAT_IEEE_FLOAT)) - || (pfmt->channels > 4) - || (!pfmt->channels) - || (!pfmt->freqHz) - || (pfmt->bitspersample == 0) - || (pfmt->bitspersample > 32)) return false; - WAVEDATAHEADER *pdata; - for (;;) + WAVReader wavFile(file); + + if(!wavFile.IsValid() + || wavFile.GetNumChannels() == 0 + || wavFile.GetNumChannels() > MAX_BASECHANNELS + || wavFile.GetBitsPerSample() > 32 + || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat)) { - pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos); - if (pdata->id_data == IFFID_data) break; - dwMemPos += pdata->length + 8; - if (dwMemPos >= dwMemLength - 8) return false; + return false; } + + m_nChannels = Util::Max(wavFile.GetNumChannels(), uint16(2)); + if(Patterns.Insert(0, 64) || Patterns.Insert(1, 64)) + { + return false; + } + + const SmpLength sampleLength = wavFile.GetSampleLength(); + + // Setting up module length + // Calculate sample length in ticks at tempo 125 + const uint32 sampleTicks = ((sampleLength * 50) / wavFile.GetSampleRate()) + 1; + uint32 ticksPerRow = Util::Max((sampleTicks + 63u) / 63u, 1u); + + Order.clear(); + Order.Append(0); + ORDERINDEX numOrders = 1; + while(ticksPerRow >= 32) + { + Order.Append(1); + + numOrders++; + ticksPerRow = (sampleTicks + (64 * numOrders - 1)) / (64 * numOrders); + if(numOrders == MAX_ORDERS) + { + break; + } + } + m_nType = MOD_TYPE_WAV; - m_nSamples = 0; + m_nSamples = wavFile.GetNumChannels(); m_nInstruments = 0; - m_nChannels = 4; - m_nDefaultSpeed = 8; + m_nDefaultSpeed = ticksPerRow; m_nDefaultTempo = 125; - m_dwSongFlags = SONG_LINEARSLIDES; // For no resampling - Order.resize(MAX_ORDERS, Order.GetInvalidPatIndex()); - Order[0] = 0; - bool fail = Patterns.Insert(0, 64); - fail = Patterns.Insert(1, 64); - if(fail) return true; - UINT samplesize = ((pfmt->channels * pfmt->bitspersample) + 7) / 8; - SmpLength len = pdata->length; - if (len > dwMemLength - 8 - dwMemPos) len = dwMemLength - dwMemPos - 8; - len /= samplesize; - LimitMax(len, MAX_SAMPLE_LENGTH); - if (!len) return true; - // Setting up module length - DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1; - DWORD framesperrow = (dwTime + 63) / 63; - if (framesperrow < 4) framesperrow = 4; - UINT norders = 1; - while (framesperrow >= 0x20) + m_dwSongFlags = SONG_LINEARSLIDES; + + for(CHANNELINDEX channel = 0; channel < wavFile.GetNumChannels(); channel++) { - Order[norders++] = 1; - Order[norders] = 0xFF; - framesperrow = (dwTime + (64 * norders - 1)) / (64 * norders); - if (norders >= MAX_ORDERS-1) break; + ChnSettings[channel].nPan = (channel % 2) ? 256 : 0; + ChnSettings[channel].nVolume = 64; + ChnSettings[channel].dwFlags = 0; } - m_nDefaultSpeed = framesperrow; - for (UINT iChn=0; iChn<4; iChn++) - { - ChnSettings[iChn].nPan = (iChn & 1) ? 256 : 0; - ChnSettings[iChn].nVolume = 64; - ChnSettings[iChn].dwFlags = 0; - } - // Setting up speed command - ModCommand *pcmd = Patterns[0]; - pcmd[0].command = CMD_SPEED; - pcmd[0].param = (BYTE)m_nDefaultSpeed; - pcmd[0].note = 5*12+1; - pcmd[0].instr = 1; - pcmd[1].note = pcmd[0].note; - pcmd[1].instr = pcmd[0].instr; - m_nSamples = pfmt->channels; - // Support for Multichannel Wave - FileReader file((char*)(lpStream + dwMemPos + 8), dwMemLength - dwMemPos - 8); - for (UINT nChn=0; nChn<m_nSamples; nChn++) + // Setting up pattern + PatternRow pattern = Patterns[0].GetRow(0); + pattern[0].note = pattern[1].note = NOTE_MIDDLEC; + pattern[0].instr = pattern[1].instr = 1; + + const FileReader sampleChunk = wavFile.GetSampleData(); + + // Read every channel into its own sample lot. + for(SAMPLEINDEX channel = 0; channel < GetNumSamples(); channel++) { - ModSample &sample = Samples[nChn + 1]; - pcmd[nChn].note = pcmd[0].note; - pcmd[nChn].instr = (BYTE)(nChn+1); + pattern[channel].note = pattern[0].note; + pattern[channel].instr = static_cast<ModCommand::INSTR>(channel + 1); + + ModSample &sample = Samples[channel + 1]; sample.Initialize(); - sample.nLength = len; - sample.nC5Speed = pfmt->freqHz; sample.uFlags = CHN_PANNING; - if (m_nSamples > 1) + sample.nLength = sampleLength; + sample.nC5Speed = wavFile.GetSampleRate(); + wavFile.ApplySampleSettings(sample, m_szNames[channel + 1]); + + if(wavFile.GetNumChannels() > 1) { - switch(nChn) + // Pan all samples appropriately + switch(channel) { - case 0: sample.nPan = 0; break; - case 1: sample.nPan = 256; break; - case 2: sample.nPan = (m_nSamples == 3 ? 128u : 64u); pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break; - case 3: sample.nPan = 192; pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break; - default: sample.nPan = 128; break; + case 0: + sample.nPan = 0; + break; + case 1: + sample.nPan = 256; + break; + case 2: + sample.nPan = (wavFile.GetNumChannels() == 3 ? 128u : 64u); + pattern[channel].command = CMD_S3MCMDEX; + pattern[channel].param = 0x91; + break; + case 3: + sample.nPan = 192; + pattern[channel].command = CMD_S3MCMDEX; + pattern[channel].param = 0x91; + break; + default: + sample.nPan = 128; + break; } } - if(pfmt->format == WAVE_FORMAT_IEEE_FLOAT) + if(wavFile.GetBitsPerSample() > 8) { sample.uFlags |= CHN_16BIT; - CopyWavChannel<ReadFloat32toInt16PCM<littleEndian32> >(sample, file, nChn, m_nSamples); + } + + if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) + { + CopyWavChannel<ReadFloat32toInt16PCM<littleEndian32> >(sample, sampleChunk, channel, wavFile.GetNumChannels()); } else { - if(pfmt->bitspersample <= 8) + if(wavFile.GetBitsPerSample() <= 8) { - CopyWavChannel<ReadInt8PCM<0x80u> >(sample, file, nChn, m_nSamples); - } else if(pfmt->bitspersample <= 16) + CopyWavChannel<ReadInt8PCM<0x80u> >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + } else if(wavFile.GetBitsPerSample() <= 16) { - sample.uFlags |= CHN_16BIT; - CopyWavChannel<ReadInt16PCM<0, littleEndian16> >(sample, file, nChn, m_nSamples); - } else if(pfmt->bitspersample <= 24) + CopyWavChannel<ReadInt16PCM<0, littleEndian16> >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + } else if(wavFile.GetBitsPerSample() <= 24) { - sample.uFlags |= CHN_16BIT; - CopyWavChannel<ReadBigIntTo16PCM<3, 1, 2> >(sample, file, nChn, m_nSamples); - } else if(pfmt->bitspersample <= 32) + CopyWavChannel<ReadBigIntTo16PCM<3, 1, 2> >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + } else if(wavFile.GetBitsPerSample() <= 32) { - sample.uFlags |= CHN_16BIT; - CopyWavChannel<ReadBigIntTo16PCM<4, 2, 3> >(sample, file, nChn, m_nSamples); + CopyWavChannel<ReadBigIntTo16PCM<4, 2, 3> >(sample, sampleChunk, channel, wavFile.GetNumChannels()); } } } + return true; } @@ -170,76 +177,62 @@ //////////////////////////////////////////////////////////////////////// // IMA ADPCM Support -#pragma pack(push, 1) -typedef struct IMAADPCMBLOCK +// Note: Only works for mono samples. +bool IMAADPCMUnpack16(int16 *target, SmpLength sampleLen, const void *source, size_t sourceSize, uint16 blockAlign) +//----------------------------------------------------------------------------------------------------------------- { - WORD sample; - BYTE index; - BYTE Reserved; -} DVI_ADPCMBLOCKHEADER; + static const int32 IMAIndexTab[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; + static const int32 IMAUnpackTable[90] = + { + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767, 0 + }; -#pragma pack(pop) + if ((sampleLen < 4) || (!target) || (!source) + || (blockAlign < 5) || (blockAlign > sourceSize)) return false; + SmpLength nPos = 0; -static const int gIMAUnpackTable[90] = -{ - 7, 8, 9, 10, 11, 12, 13, 14, - 16, 17, 19, 21, 23, 25, 28, 31, - 34, 37, 41, 45, 50, 55, 60, 66, - 73, 80, 88, 97, 107, 118, 130, 143, - 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, - 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, - 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, - 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, - 32767, 0 -}; - - -BOOL IMAADPCMUnpack16(signed short *pdest, UINT nLen, LPBYTE psrc, DWORD dwBytes, UINT pkBlkAlign) -//------------------------------------------------------------------------------------------------ -{ - static const int gIMAIndexTab[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; - UINT nPos; - int value; - - if ((nLen < 4) || (!pdest) || (!psrc) - || (pkBlkAlign < 5) || (pkBlkAlign > dwBytes)) return false; - nPos = 0; - while ((nPos < nLen) && (dwBytes > 4)) + const uint8 *psrc = static_cast<const uint8 *>(source); + while((nPos < sampleLen) && (sourceSize > 4)) { - int nIndex; - value = *((short int *)psrc); + int32 nIndex; + int32 value = *((int16 *)psrc); nIndex = psrc[2]; psrc += 4; - dwBytes -= 4; - pdest[nPos++] = (short int)value; - for (UINT i=0; ((i<(pkBlkAlign-4)*2) && (nPos < nLen) && (dwBytes)); i++) + sourceSize -= 4; + target[nPos++] = (int16)value; + for(uint32 i = 0; (i < (blockAlign - 4u) * 2u) && (nPos < sampleLen) && sourceSize > 0; i++) { - BYTE delta; - if (i & 1) + uint8 delta; + if(i & 1) { - delta = (BYTE)(((*(psrc++)) >> 4) & 0x0F); - dwBytes--; + delta = ((*(psrc++)) >> 4) & 0x0F; + sourceSize--; } else { - delta = (BYTE)((*psrc) & 0x0F); + delta = (*psrc) & 0x0F; } - int v = gIMAUnpackTable[nIndex] >> 3; - if (delta & 1) v += gIMAUnpackTable[nIndex] >> 2; - if (delta & 2) v += gIMAUnpackTable[nIndex] >> 1; - if (delta & 4) v += gIMAUnpackTable[nIndex]; + int32 v = IMAUnpackTable[nIndex] >> 3; + if (delta & 1) v += IMAUnpackTable[nIndex] >> 2; + if (delta & 2) v += IMAUnpackTable[nIndex] >> 1; + if (delta & 4) v += IMAUnpackTable[nIndex]; if (delta & 8) value -= v; else value += v; - nIndex += gIMAIndexTab[delta & 7]; + nIndex += IMAIndexTab[delta & 7]; if (nIndex < 0) nIndex = 0; else if (nIndex > 88) nIndex = 88; - Limit(value, -32768, 32767); - pdest[nPos++] = (short int)value; + target[nPos++] = static_cast<int16>(Clamp(value, -32768, 32767)); } } return true; } - - Modified: trunk/OpenMPT/soundlib/Loaders.h =================================================================== --- trunk/OpenMPT/soundlib/Loaders.h 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/Loaders.h 2012-05-27 15:52:58 UTC (rev 1287) @@ -33,7 +33,11 @@ size_t streamPos; // Cursor location in the file public: + // Initialize invalid file reader object. + FileReader() : streamData(nullptr), streamLength(0), streamPos(0) { } + // Initialize file reader object with pointer to data and data length. FileReader(const char *data, size_t length) : streamData(data), streamLength(length), streamPos(0) { } + // Initialize file reader object based on an existing file reader object. The other object's stream position is copied. FileReader(const FileReader &other) : streamData(other.streamData), streamLength(other.streamLength), streamPos(other.streamPos) { } // Returns true if the object points to a valid stream. @@ -126,7 +130,7 @@ return FileReader(streamData + position, Util::Min(length, streamLength - position)); } else { - return FileReader(nullptr, 0); + return FileReader(); } } @@ -330,12 +334,12 @@ // Allow to read a struct partially (if there's less memory available than the struct's size, fill it up with zeros). // The file cursor is advanced by "partialSize" bytes. template <typename T> - bool ReadStructPartial(T &target, size_t partialSize = sizeof(target)) + bool ReadStructPartial(T &target, size_t partialSize = sizeof(T)) { const size_t copyBytes = Util::Min(partialSize, sizeof(target), BytesLeft()); memcpy(&target, streamData + streamPos, copyBytes); - memset(reinterpret_cast<const char *>(&target) + copyBytes, 0, sizeof(target) - copyBytes); + memset(reinterpret_cast<char *>(&target) + copyBytes, 0, sizeof(target) - copyBytes); Skip(partialSize); return true; @@ -420,9 +424,25 @@ && std::numeric_limits<T>::is_signed == false, "Target type is a not an unsigned integer"); - target = 0; + if(!BytesLeft()) + { + target = 0; + return false; + } + size_t writtenBits = 0; - uint8 b = 0x80; + uint8 b = ReadUint8(); + target = (b & 0x7F); + + // Count actual bits used in most significant byte (i.e. this one) + for(size_t bit = 0; bit < 7; bit++) + { + if((b & (1 << bit)) != 0) + { + writtenBits = bit + 1; + } + } + while(BytesLeft() && (b & 0x80) != 0) { b = ReadUint8(); @@ -434,7 +454,7 @@ if(writtenBits > sizeof(target) * 8) { // Overflow - target = std::numeric_limits<T>::max; + target = Util::MaxValueOfType<T>(target); return false; } else if((b & 0x80) != 0) { @@ -447,4 +467,4 @@ }; #include "Sndfile.h" -#include "SampleIO.h" \ No newline at end of file +#include "SampleIO.h" Modified: trunk/OpenMPT/soundlib/ModSample.h =================================================================== --- trunk/OpenMPT/soundlib/ModSample.h 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/ModSample.h 2012-05-27 15:52:58 UTC (rev 1287) @@ -28,8 +28,8 @@ uint8 nVibSweep; // Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full strength) uint8 nVibDepth; // Auto vibrato depth uint8 nVibRate; // Auto vibrato rate (speed) - //CHAR name[MAX_SAMPLENAME]; // Maybe it would be nicer to have sample names here, but that would require some refactoring. Also, would this slow down the mixer (cache misses)? - CHAR filename[MAX_SAMPLEFILENAME]; + //char name[MAX_SAMPLENAME]; // Maybe it would be nicer to have sample names here, but that would require some refactoring. Also, would this slow down the mixer (cache misses)? + char filename [MAX_SAMPLEFILENAME]; // Return the size of one (elementary) sample in bytes. uint8 GetElementarySampleSize() const { return (uFlags & CHN_16BIT) ? 2 : 1; } Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-05-27 15:52:58 UTC (rev 1287) @@ -18,19 +18,18 @@ #include "Wav.h" #include "ITTools.h" #include "XMTools.h" -#include "../common/StringFixer.h" +#include "WAVTools.h" #include "../common/Reporting.h" #include "../mptrack/version.h" #include "ChunkReader.h" -#pragma warning(disable:4244) bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength) //-------------------------------------------------------------------------------------------------- { FileReader file(reinterpret_cast<const char *>(lpMemFile), dwFileLength); if(!nSample || nSample >= MAX_SAMPLES) return false; - if(!ReadWAVSample(nSample, lpMemFile, dwFileLength) + if(!ReadWAVSample(nSample, file) && !ReadXISample(nSample, lpMemFile, dwFileLength) && !ReadAIFFSample(nSample, file) && !ReadITSSample(nSample, lpMemFile, dwFileLength) @@ -297,307 +296,75 @@ //////////////////////////////////////////////////////////////////////////////// // WAV Open -#define IFFID_pcm 0x206d6370 -#define IFFID_fact 0x74636166 +extern bool IMAADPCMUnpack16(int16 *target, SmpLength sampleLen, const void *source, size_t sourceSize, uint16 blockAlign); -extern BOOL IMAADPCMUnpack16(signed short *pdest, UINT nLen, LPBYTE psrc, DWORD dwBytes, UINT pkBlkAlign); - -bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength, DWORD *pdwWSMPOffset) -//------------------------------------------------------------------------------------------------------------------- +bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, FileReader *wsmpChunk) +//------------------------------------------------------------------------------------------ { - DWORD dwMemPos = 0, dwDataPos; - WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpMemFile; - WAVEFORMATHEADER *pfmt, *pfmtpk; - WAVEDATAHEADER *pdata; - WAVESMPLHEADER *psh; - WAVEEXTRAHEADER *pxh; - DWORD dwInfoList, dwFact, dwSamplesPerBlock; - - if (!nSample || !lpMemFile || (dwFileLength < sizeof(WAVEFILEHEADER) + sizeof(WAVEFORMATHEADER))) - return false; - if ((phdr->id_RIFF != LittleEndian(IFFID_RIFF) && phdr->id_RIFF != LittleEndian(IFFID_LIST)) - || (phdr->id_WAVE != LittleEndian(IFFID_WAVE) && phdr->id_WAVE != LittleEndian(IFFID_wave))) - return false; + WAVReader wavFile(file); - dwMemPos = sizeof(WAVEFILEHEADER); - dwDataPos = 0; - pfmt = NULL; - pfmtpk = NULL; - pdata = NULL; - psh = NULL; - pxh = NULL; - dwSamplesPerBlock = 0; - dwInfoList = 0; - dwFact = 0; - - while ((dwMemPos + 8 < dwFileLength) && (dwMemPos < phdr->filesize)) + if(!wavFile.IsValid() + || wavFile.GetNumChannels() == 0 + || wavFile.GetNumChannels() > 2 + || wavFile.GetBitsPerSample() > 32 + || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM)) { - uint32 dwIFFID = LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwMemPos)); - uint32 dwLen = LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwMemPos + 4)); - if ((dwLen > dwFileLength) || (dwMemPos + 8 + dwLen > dwFileLength)) - break; - - switch(dwIFFID) - { - // "fmt " - case IFFID_fmt: - if (pfmt) break; - if (dwLen + 8 >= sizeof(WAVEFORMATHEADER)) - { - pfmt = (WAVEFORMATHEADER *)(lpMemFile + dwMemPos); - if (dwLen + 8 >= sizeof(WAVEFORMATHEADER)+4) - { - dwSamplesPerBlock = LittleEndianW(*reinterpret_cast<uint16 *>(lpMemFile + dwMemPos + sizeof(WAVEFORMATHEADER) + 2)); - } - } - break; - // "pcm " - case IFFID_pcm: - if (pfmtpk) break; - if (dwLen+8 >= sizeof(WAVEFORMATHEADER)) pfmtpk = (WAVEFORMATHEADER *)(lpMemFile + dwMemPos); - break; - // "fact" - case IFFID_fact: - if (!dwFact) dwFact = LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwMemPos + 8)); - break; - // "data" - case IFFID_data: - if(dwLen + 8 >= sizeof(WAVEDATAHEADER) && !pdata) - { - pdata = (WAVEDATAHEADER *)(lpMemFile + dwMemPos); - dwDataPos = dwMemPos + 8; - } - break; - // "xtra" - case 0x61727478: - if(dwLen + 8 >= sizeof(WAVEEXTRAHEADER)) - { - pxh = (WAVEEXTRAHEADER *)(lpMemFile + dwMemPos); - if(LittleEndian(pxh->xtra_len) + 8 > dwFileLength - dwMemPos) - { - pxh = nullptr; - } - } - break; - // "smpl" - case 0x6C706D73: - if(dwLen + 8 >= sizeof(WAVESMPLHEADER)) - psh = (WAVESMPLHEADER *)(lpMemFile + dwMemPos); - break; - // "LIST"."info" - case IFFID_LIST: - if(*reinterpret_cast<uint32 *>(lpMemFile + dwMemPos + 8) == LittleEndian(IFFID_INFO)) // "INFO" - dwInfoList = dwMemPos; - break; - // "wsmp": - case IFFID_wsmp: - if (pdwWSMPOffset) *pdwWSMPOffset = dwMemPos; - 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; - - if ((pfmtpk) && (pfmt)) - { - if (pfmt->format != 1) - { - WAVEFORMATHEADER *tmp = pfmt; - pfmt = pfmtpk; - pfmtpk = tmp; - if(pfmtpk->format != 0x11 || pfmtpk->bitspersample != 4 - || pfmtpk->channels != 1) - return false; - } else pfmtpk = NULL; } - uint16 wavFormat = LittleEndianW(pfmt->format); - uint16 channels = LittleEndianW(pfmt->channels); - uint16 bitsPerSmp = LittleEndianW(pfmt->bitspersample); - - // WAVE_FORMAT_PCM (1), WAVE_FORMAT_IEEE_FLOAT (3), WAVE_FORMAT_EXTENSIBLE (0xFFFE) - if (((wavFormat != 1 && wavFormat != 0xFFFE) - && (wavFormat != 3 || bitsPerSmp != 32)) //Microsoft IEEE FLOAT - || channels > 2 - || channels == 0 - || bitsPerSmp == 0 - || bitsPerSmp > 32 - ) return false; - DestroySample(nSample); - ModSample &sample = Samples[nSample]; - MemsetZero(m_szNames[nSample]); sample.Initialize(); - sample.nC5Speed = LittleEndian(pfmt->freqHz); + sample.nLength = wavFile.GetSampleLength(); + sample.nC5Speed = wavFile.GetSampleRate(); + wavFile.ApplySampleSettings(sample, m_szNames[nSample]); + sample.Convert(MOD_TYPE_IT, GetType()); - // IMA ADPCM 4:1 - if (pfmtpk) + FileReader sampleChunk = wavFile.GetSampleData(); + + if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtIMA_ADPCM) { - if (dwFact < 4) dwFact = LittleEndian(pdata->length) * 2; - sample.nLength = dwFact; + // IMA ADPCM 4:1 LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); - sample.pSample = AllocateSample(sample.nLength * 2 + 16); - IMAADPCMUnpack16((signed short *)sample.pSample, sample.nLength, - (LPBYTE)(lpMemFile + dwDataPos), dwFileLength - dwDataPos, LittleEndianW(pfmtpk->samplesize)); + sample.uFlags |= CHN_16BIT; + if(!sample.AllocateSample()) + { + return false; + } + IMAADPCMUnpack16((int16 *)sample.pSample, sample.nLength, sampleChunk.GetRawData(), sampleChunk.BytesLeft(), wavFile.GetBlockAlign()); AdjustSampleLoop(sample); } else { - // Some samples have an incorrect blockAlign/sample size set (e.g. it's 8 in SQUARE.WAV while it should be 1), so let's better not trust this value. - sample.nLength = LittleEndian(pdata->length) / (((channels * bitsPerSmp) + 7) / 8); - + // PCM / Float SampleIO sampleIO( SampleIO::_8bit, - (channels > 1) ? SampleIO::stereoInterleaved : SampleIO::mono, + (wavFile.GetNumChannels() > 1) ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, - (bitsPerSmp > 8) ? SampleIO::signedPCM : SampleIO::unsignedPCM); + (wavFile.GetBitsPerSample() > 8) ? SampleIO::signedPCM : SampleIO::unsignedPCM); - if(bitsPerSmp <= 8) + if(wavFile.GetBitsPerSample() <= 8) sampleIO |= SampleIO::_8bit; - else if(bitsPerSmp <= 16) + else if(wavFile.GetBitsPerSample() <= 16) sampleIO |= SampleIO::_16bit; - else if(bitsPerSmp <= 24) + else if(wavFile.GetBitsPerSample() <= 24) sampleIO |= SampleIO::_24bit; - else if(bitsPerSmp <= 32) + else if(wavFile.GetBitsPerSample() <= 32) sampleIO |= SampleIO::_32bit; - if(wavFormat == 3 /*WAVE_FORMAT_IEEE_FLOAT*/) + if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) { sampleIO |= SampleIO::floatPCM; } - sampleIO.ReadSample(sample, (LPSTR)(lpMemFile + dwDataPos), dwFileLength - dwDataPos); + sampleIO.ReadSample(sample, sampleChunk); } - - bool fixSampleLoops = false; - // LIST field - if (dwInfoList) + if(wsmpChunk != nullptr) { - uint32 dwLSize = LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwInfoList + 4)) + 8; - uint32 d = 12; - while (d + 8 < dwLSize) - { - if (!lpMemFile[dwInfoList + d]) d++; - uint32 id = LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwInfoList + d)); - uint32 len = LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwInfoList + d + 4)); - - if ((dwInfoList + d + 8 + len <= dwFileLength) && (len)) - { - switch(id) - { - case IFFID_INAM: - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[nSample], reinterpret_cast<const char *>(lpMemFile + dwInfoList + d + 8), len); - if (phdr->id_RIFF != LittleEndian(IFFID_RIFF)) - { - // DLS sample -> sample filename - StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, reinterpret_cast<const char *>(lpMemFile + dwInfoList + d + 8), len); - } - break; - - case IFFID_ISFT: - { - // MPT / old versions of OpenMPT stored the sample loop information incorrectly: - // In the RIFF standard, the loop end point is *inclusive*, in OpenMPT it's *exclusive*. - char *softwareId = reinterpret_cast<char *>(lpMemFile + dwInfoList + d + 8); - fixSampleLoops = !strncmp(softwareId, "Modplug Tracker", min(len, 16)); - } - break; - } - } - d += 8 + len; - } + // DLS WSMP chunk + *wsmpChunk = wavFile.GetWsmpChunk(); } - // smpl field - if (psh) - { - sample.nLoopStart = sample.nLoopEnd = 0; - int numLoops = LittleEndian(psh->dwSampleLoops); - if(numLoops && (sizeof(WAVESMPLHEADER) + numLoops * sizeof(SAMPLELOOPSTRUCT) <= LittleEndian(psh->smpl_len) + 8)) - { - SAMPLELOOPSTRUCT *psl = (SAMPLELOOPSTRUCT *)(&psh[1]); - if(numLoops > 1) - { - sample.uFlags |= (CHN_LOOP | CHN_SUSTAINLOOP); - if(LittleEndian(psl[0].dwLoopType)) sample.uFlags |= CHN_PINGPONGSUSTAIN; - if(LittleEndian(psl[1].dwLoopType)) sample.uFlags |= CHN_PINGPONGLOOP; - sample.nSustainStart = LittleEndian(psl[0].dwLoopStart); - sample.nSustainEnd = LittleEndian(psl[0].dwLoopEnd); - sample.nLoopStart = LittleEndian(psl[1].dwLoopStart); - sample.nLoopEnd = LittleEndian(psl[1].dwLoopEnd); - } else - { - sample.uFlags |= CHN_LOOP; - if(LittleEndian(psl->dwLoopType)) sample.uFlags |= CHN_PINGPONGLOOP; - sample.nLoopStart = LittleEndian(psl->dwLoopStart); - sample.nLoopEnd = LittleEndian(psl->dwLoopEnd); - } - - if(!fixSampleLoops) - { - // RIFF loop end points are inclusive - if(sample.nLoopEnd < sample.nLength && (sample.uFlags & CHN_LOOP)) - { - sample.nLoopEnd++; - } - - if(sample.nSustainEnd < sample.nLength && (sample.uFlags & CHN_SUSTAINLOOP)) - { - sample.nSustainEnd++; - } - } - - if (sample.nLoopStart >= sample.nLoopEnd) sample.uFlags &= ~(CHN_LOOP|CHN_PINGPONGLOOP); - if (sample.nSustainStart >= sample.nSustainEnd) sample.uFlags &= ~(CHN_PINGPONGLOOP|CHN_PINGPONGSUSTAIN); - } - } - - // xtra field - if (pxh) - { - DWORD extFlags = LittleEndian(pxh->dwFlags); - if (extFlags & CHN_PINGPONGLOOP) sample.uFlags |= CHN_PINGPONGLOOP; - if (extFlags & CHN_SUSTAINLOOP) sample.uFlags |= CHN_SUSTAINLOOP; - if (extFlags & CHN_PINGPONGSUSTAIN) sample.uFlags |= CHN_PINGPONGSUSTAIN; - if (extFlags & CHN_PANNING) sample.uFlags |= CHN_PANNING; - - sample.nPan = LittleEndianW(pxh->wPan); - sample.nVolume = LittleEndianW(pxh->wVolume); - sample.nGlobalVol = LittleEndianW(pxh->wGlobalVol); - sample.nVibType = pxh->nVibType; - sample.nVibSweep = pxh->nVibSweep; - sample.nVibDepth = pxh->nVibDepth; - sample.nVibRate = pxh->nVibRate; - // Name present (clipboard only) - UINT xtrabytes = LittleEndian(pxh->xtra_len) - (sizeof(WAVEEXTRAHEADER) - 8); - LPSTR pszTextEx = (LPSTR)(pxh + 1); - if (xtrabytes >= MAX_SAMPLENAME) - { - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[nSample], pszTextEx, MAX_SAMPLENAME); - pszTextEx += MAX_SAMPLENAME; - xtrabytes -= MAX_SAMPLENAME; - if(xtrabytes > 0) - { - StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, pszTextEx, xtrabytes); - } - } - } - sample.Convert(MOD_TYPE_IT, GetType()); return true; } @@ -606,8 +373,8 @@ // Save WAV -bool CSoundFile::SaveWAVSample(UINT nSample, const LPCSTR lpszFileName) const -//--------------------------------------------------------------------------- +bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const +//---------------------------------------------------------------------------------- { char *softwareId = "OpenMPT " MPT_VERSION_STR; size_t softwareIdLength = strlen(softwareId) + 1; @@ -714,6 +481,11 @@ list.list_len = LittleEndian(softwareIdLength); fwrite(&list, 1, 8, f); fwrite(softwareId, 1, list.list_len, f); + if((softwareIdLength % 2) != 0) + { + int8 padding = 0; + fwrite(&padding, 1, 1, f); + } // "xtra" field extra.xtra_id = LittleEndian(IFFID_xtra); @@ -743,8 +515,8 @@ /////////////////////////////////////////////////////////////// // Save RAW -bool CSoundFile::SaveRAWSample(UINT nSample, const LPCSTR lpszFileName) const -//--------------------------------------------------------------------------- +bool CSoundFile::SaveRAWSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const +//---------------------------------------------------------------------------------- { FILE *f; if ((f = fopen(lpszFileName, "wb")) == NULL) return false; @@ -875,8 +647,8 @@ } -void PatchToSample(CSoundFile *that, UINT nSample, LPBYTE lpStream, DWORD dwMemLength) -//------------------------------------------------------------------------------------ +void PatchToSample(CSoundFile *that, SAMPLEINDEX nSample, LPBYTE lpStream, DWORD dwMemLength) +//------------------------------------------------------------------------------------------- { ModSample &sample = that->GetSample(nSample); DWORD dwMemPos = sizeof(GF1SAMPLEHEADER); @@ -901,8 +673,11 @@ sample.nVibDepth = psh->vibrato_depth; sample.nVibRate = psh->vibrato_rate/4; CSoundFile::FrequencyToTranspose(&sample); - sample.RelativeTone += 84 - PatchFreqToNote(psh->root_freq); - if (psh->scale_factor) sample.RelativeTone -= psh->scale_frequency - 60; + sample.RelativeTone += static_cast<uint8>(84 - PatchFreqToNote(psh->root_freq)); + if(psh->scale_factor) + { + sample.RelativeTone = static_cast<uint8>(sample.RelativeTone - psh->scale_frequency - 60); + } sample.nC5Speed = CSoundFile::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); SampleIO sampleIO( @@ -983,9 +758,9 @@ pIns->nNNA = NNA_NOTEOFF; pIns->nDNA = DNA_NOTEFADE; } - UINT nFreeSmp = 0; + SAMPLEINDEX nFreeSmp = 0; UINT nMinSmpNote = 0xff; - UINT nMinSmp = 0; + SAMPLEINDEX nMinSmp = 0; for (UINT iSmp=0; iSmp<nSamples; iSmp++) { // Find a free sample @@ -1389,7 +1164,7 @@ }; uint32 magic; // FORM - uint32 length; // Size of the file, not including magic an length + uint32 length; // Size of the file, not including magic and length uint32 type; // AIFF or AIFC // Convert all multi-byte numeric values to current platform's endianness or vice versa. @@ -1414,6 +1189,8 @@ idNAME = 0x4E414D45, }; + typedef ChunkIdentifiers id_type; + uint32 id; // See ChunkIdentifiers uint32 length; // Chunk size without header @@ -1562,8 +1339,7 @@ // Read COMM chunk FileReader commChunk(chunks.GetChunk(AIFFChunk::idCOMM)); AIFFCommonChunk sampleInfo; - if(!commChunk.IsValid() - || !commChunk.ReadConvertEndianness(sampleInfo)) + if(!commChunk.ReadConvertEndianness(sampleInfo)) { return false; } @@ -1591,8 +1367,7 @@ // Read SSND chunk FileReader soundChunk(chunks.GetChunk(AIFFChunk::idSSND)); AIFFSoundChunk sampleHeader; - if(!soundChunk.IsValid() - || !soundChunk.ReadConvertEndianness(sampleHeader) + if(!soundChunk.ReadConvertEndianness(sampleHeader) || soundChunk.BytesLeft() <= sampleHeader.offset) { return false; @@ -1643,9 +1418,8 @@ // Read MARK and INST chunk to extract sample loops FileReader markerChunk(chunks.GetChunk(AIFFChunk::idMARK)); - FileReader instChunk(chunks.GetChunk(AIFFChunk::idINST)); AIFFInstrumentChunk instrHeader; - if(markerChunk.IsValid() && instChunk.IsValid() && instChunk.ReadConvertEndianness(instrHeader)) + if(markerChunk.IsValid() && chunks.GetChunk(AIFFChunk::idINST).ReadConvertEndianness(instrHeader)) { size_t numMarkers = markerChunk.ReadUint16BE(); @@ -1760,7 +1534,7 @@ //---------------------------------------------------------------------------------------------- { ITInstrument *pinstr = (ITInstrument *)lpMemFile; - UINT nsmp = 0, nsamples; + SAMPLEINDEX nsmp = 0, nsamples; if ((!lpMemFile) || (dwFileLength < sizeof(ITInstrument)) || (pinstr->id != LittleEndian(ITInstrument::magic))) return false; @@ -1862,9 +1636,9 @@ { // We haven't considered this sample yet. smptable.push_back(smp); - smpmap[smp - 1] = smptable.size(); + smpmap[smp - 1] = static_cast<SAMPLEINDEX>(smptable.size()); } - iti.iti.keyboard[i * 2 + 1] = smpmap[smp - 1]; + iti.iti.keyboard[i * 2 + 1] = static_cast<uint8>(smpmap[smp - 1]); } else { iti.iti.keyboard[i * 2 + 1] = 0; @@ -2049,8 +1823,8 @@ -bool CSoundFile::Read8SVXSample(UINT nSample, LPBYTE lpMemFile, DWORD dwFileLength) -//--------------------------------------------------------------------------------- +bool CSoundFile::Read8SVXSample(SAMPLEINDEX nSample, LPBYTE lpMemFile, DWORD dwFileLength) +//---------------------------------------------------------------------------------------- { IFF8SVXFILEHEADER *pfh = (IFF8SVXFILEHEADER *)lpMemFile; IFFVHDR *pvh = (IFFVHDR *)(lpMemFile + 12); Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-27 15:52:58 UTC (rev 1287) @@ -611,7 +611,7 @@ && !ReadIT(lpStream, dwMemLength) /*&& !ReadMPT(lpStream, dwMemLength)*/ && !ReadS3M(file) - && !ReadWav(lpStream, dwMemLength) + && !ReadWav(file) #ifndef MODPLUG_BASIC_SUPPORT && !ReadSTM(lpStream, dwMemLength) && !ReadMed(lpStream, dwMemLength) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-05-26 14:55:51 UTC (rev 1286) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-05-27 15:52:58 UTC (rev 1287) @@ -18,7 +18,6 @@ #include <bitset> #include <set> #include "Snd_defs.h" -#include "Endianness.h" #include "tuning.h" #include "MIDIMacros.h" #ifdef MODPLUG_TRACKER @@ -389,7 +388,7 @@ bool ReadITProject(const LPCBYTE lpStream, const DWORD dwMemLength); // -> CODE#0023 -> DESC="IT project files (.itp)" -! NEW_FEATURE#0023 bool Read669(FileReader &file); bool ReadUlt(const LPCBYTE lpStream, const DWORD dwMemLength); - bool ReadWav(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadWav(FileReader &file); bool ReadDSM(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadFAR(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadAMS(const LPCBYTE lpStream, const DWORD dwMemLength); @@ -624,15 +623,15 @@ // Samples file I/O bool ReadSampleFromFile(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); - bool ReadWAVSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength, DWORD *pdwWSMPOffset=NULL); + bool ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, FileReader *wsmpChunk = nullptr); bool ReadPATSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); bool ReadS3ISample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); bool ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file); bool ReadXISample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); UINT ReadITSSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength, DWORD dwOffset=0); - bool Read8SVXSample(UINT nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); - bool SaveWAVSample(UINT nSample, const LPCSTR lpszFileName) const; - bool SaveRAWSample(UINT nSample, const LPCSTR lpszFileName) const; + bool Read8SVXSample(SAMPLEINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); + bool SaveWAVSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const; + bool SaveRAWSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const; // Instrument file I/O bool ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); Added: trunk/OpenMPT/soundlib/WAVTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.cpp (rev 0) +++ trunk/OpenMPT/soundlib/WAVTools.cpp 2012-05-27 15:52:58 UTC (rev 1287) @@ -0,0 +1,191 @@ +/* + * WAVTools.cpp + * ------------ + * Purpose: Definition of WAV file structures and helper functions + * 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 "WAVTools.h" + + +WAVReader::WAVReader(FileReader &inputFile) : file(inputFile) +//----------------------------------------------------------- +{ + file.Rewind(); + + RIFFHeader fileHeader; + if(!file.ReadConvertEndianness(fileHeader) + || (fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST) + || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave)) + { + return; + } + + isDLS = (fileHeader.magic == RIFFHeader::idLIST); + + ChunkReader::ChunkList<RIFFChunk> chunks = file.ReadChunks<RIFFChunk>(2); + + if(chunks.size() >= 4 + && chunks[1].GetHeader().GetID() == RIFFChunk::iddata + && chunks[1].GetHeader().GetLength() % 2 != 0 + && chunks[2].GetHeader().GetLength() == 0 + && chunks[3].GetHeader().GetID() == RIFFChunk::id____) + { + // Houston, we have a problem: Old versions of (Open)MPT didn't write RIFF padding bytes. -_- + // Luckily, the only RIFF chunk with an odd size those versions would ever write would be the "data" chunk + // (which contains the sample data), and its size is only odd iff the sample has an odd length and is in + // 8-Bit mono format. In all other cases, the sample size (and thus the chunk size) is even. + + // And we're even more lucky: The versions of (Open)MPT in question will always write a relatively small + // (smaller than 256 bytes) "smpl" chunk after the "data" chunk. This means that after an unpadded sample, + // we will always read "mpl?" (? being the length of the "smpl" chunk) as the next chunk magic. The first two + // 32-Bit members of the "smpl" chunk are always zero in our case, so we are going to read a chunk length of 0 + // next and the next chunk magic, which will always consist of four zero bytes. Hooray! We just checked for those + // four zero bytes and can be pretty confident that we should not have applied padding. + file.Seek(sizeof(RIFFHeader)); + chunks = file.ReadChunks<RIFFChunk>(1); + } + + // Read format chunk + FileReader formatChunk = chunks.GetChunk(RIFFChunk::idfmt_); + if(!formatChunk.ReadConvertEndianness(formatInfo)) + { + return; + } + if(formatInfo.format == WAVFormatChunk::fmtExtensible) + { + WAVFormatChunkExtension extFormat; + if(!formatChunk.ReadConvertEndianness(extFormat)) + { + return; + } + formatInfo.format = extFormat.subFormat; + } + + // Read sample data + sampleData = chunks.GetChunk(RIFFChunk::iddata); + + if(!sampleData.IsValid() && chunks.ChunkExists(RIFFChunk::idpcm_)) + { + // The old IMA ADPCM loader code looked for the "pcm " chunk instead of the "data" chunk... + // Dunno why, but we will just look for both. + sampleData = chunks.GetChunk(RIFFChunk::idpcm_); + } + + // "fact" chunk should contain sample length of compressed samples. + sampleLength = chunks.GetChunk(RIFFChunk::idfact).ReadUint32LE(); + + if(formatInfo.format != WAVFormatChunk::fmtIMA_ADPCM || sampleLength == 0) + { + // Some samples have an incorrect blockAlign / sample size set (e.g. it's 8 in SQUARE.WAV while it should be 1), so let's better not trust this value. + sampleLength = sampleData.GetLength() / GetSampleSize(); + } + + // Read sample loop points + FileReader smplChunk(chunks.GetChunk(RIFFChunk::idsmpl)); + WAVSampleInfoChunk sampleInfo; + if(smplChunk.ReadConvertEndianness(sampleInfo)) + { + for(size_t i = 0; i < sampleInfo.numLoops; i++) + { + WAVSampleLoop loopData; + if(smplChunk.ReadConvertEndianness(loopData)) + { + sampleLoops.push_back(loopData); + } + } + } + + // Read text chunks + ChunkReader listChunk = chunks.GetChunk(RIFFChunk::idLIST); + if(listChunk.ReadMagic("INFO")) + { + infoChunk = listChunk.ReadChunks<RIFFChunk>(2); + } + + // Read MPT sample information + xtraChunk = chunks.GetChunk(RIFFChunk::idxtra); + + // DLS bank chunk + wsmpChunk = chunks.GetChunk(RIFFChunk::idwsmp); +} + + +void WAVReader::ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]) +//---------------------------------------------------------------------------------------- +{ + // Read sample name + FileReader textChunk = infoChunk.GetChunk(RIFFChunk::idINAM); + textChunk.ReadString<StringFixer::nullTerminated>(sampleName, textChunk.GetLength()); + if(isDLS) + { + // DLS sample -> sample filename + strncpy(sample.filename, sampleName, CountOf(sample.filename)); + StringFixer::SetNullTerminator(sample.filename); + } + + // Read software name + const bool isOldMPT = infoChunk.GetChunk(RIFFChunk::idISFT).ReadMagic("Modplug Tracker"); + + sample.uFlags &= ~(CHN_LOOP | CHN_SUSTAINLOOP); + + // Convert loops + if(!sampleLoops.empty()) + { + size_t normalLoopIndex = 0; + if(sampleLoops.size() > 1) + { + sampleLoops[0].ApplyToSample(sample.nSustainStart, sample.nSustainStart, sample.nLength, sample.uFlags, CHN_SUSTAINLOOP, CHN_PINGPONGSUSTAIN, isOldMPT); + normalLoopIndex = 1; + } + sampleLoops[normalLoopIndex].ApplyToSample(sample.nLoopStart, sample.nLoopEnd, sample.nLength, sample.uFlags, CHN_LOOP, CHN_PINGPONGLOOP, isOldMPT); + } + + WAVExtraChunk mptInfo; + xtraChunk.Rewind(); + if(xtraChunk.ReadConvertEndianness(mptInfo)) + { + if(mptInfo.flags & WAVExtraChunk::bidiLoop) sample.uFlags |= CHN_PINGPONGLOOP; + if(mptInfo.flags & WAVExtraChunk::sustainLoop) sample.uFlags |= CHN_SUSTAINLOOP; + if(mptInfo.flags & WAVExtraChunk::sustainBidi) sample.uFlags |= CHN_PINGPONGSUSTAIN; + if(mptInfo.flags & WAVExtraChunk::setPanning) sample.uFlags |= CHN_PANNING; + + sample.nPan = Util::Min(mptInfo.defaultPan, uint16(256)); + sample.nVolume = Util::Min(mptInfo.defaultVolume, uint16(256)); + sample.nGlobalVol = Util::Min(mptInfo.globalVolume, uint16(64)); + sample.nVibType = mptInfo.vibratoType; + sample.nVibSweep = mptInfo.vibratoSweep; + sample.nVibDepth = mptInfo.vibratoDepth; + sample.nVibRate = mptInfo.vibratoRate; + + if(xtraChunk.BytesLeft() >= MAX_SAMPLENAME) + { + // Name present (clipboard only) + xtraChunk.ReadString<StringFixer::nullTerminated>(sampleName, MAX_SAMPLENAME); + xtraChunk.ReadString<StringFixer::nullTerminated>(sample.filename, xtraChunk.BytesLeft()); + } + } +} + + +void WAVSampleLoop::ApplyToSample(SmpLength &start, SmpLength &end, uint32 sampleLength, uint16 &flags, uint16 enableFlag, uint16 bidiFlag, bool mptLoopFix) const +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- +{ + start = Util::Min(static_cast<SmpLength>(loopStart), sampleLength); + end = Clamp(static_cast<SmpLength>(loopEnd), start, sampleLength); + if(!mptLoopFix && end < sampleLength) + { + // RIFF loop end points are inclusive - old versions of MPT didn't consider this. + end++; + } + + flags |= enableFlag; + if(loopType == loopBidi) + { + flags |= bidiFlag; + } +} Added: trunk/OpenMPT/soundlib/WAVTools.h =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.h (rev 0) +++ trunk/OpenMPT/soundlib/WAVTools.h 2012-05-27 15:52:58 UTC (rev 1287) @@ -0,0 +1,266 @@ +/* + * WAVTools.h + * ---------- + * Purpose: Definition of WAV file structures and helper functions + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "ChunkReader.h" + +#pragma pack(push, 1) + +// RIFF header +struct RIFFHeader +{ + // 32-Bit chunk identifiers + enum RIFFMagic + { + idRIFF = 0x46464952, // magic for WAV files + idLIST = 0x5453494C, // magic for samples in DLS banks + idWAVE = 0x45564157, // type for WAV files + idwave = 0x65766177, // type for samples in DLS banks + }; + + uint32 magic; // RIFF (in WAV files) or LIST (in DLS banks) + uint32 length; // Size of the file, not including magic and length + uint32 type; // WAVE (in WAV files) or wave (in DLS banks) + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(magic); + SwapBytesLE(length); + SwapBytesLE(type); + } +}; + + +// General RIFF Chunk header +struct RIFFChunk +{ + // 32-Bit chunk identifiers + enum ChunkIdentifiers + { + idfmt_ = 0x20746D66, // "fmt " + iddata = 0x61746164, // "data" + idpcm_ = 0x206d6370, // "pcm " (IMA ADPCM samples) + idfact = 0x74636166, // "fact" (compressed samples) + idsmpl = 0x6C706D73, // "smpl" + idLIST = 0x5453494C, // "LIST" + idxtra = 0x61727478, // "xtra" + idcue_ = 0x20657563, // "cue " + idwsmp = 0x706D7377, // "wsmp" (DLS bank samples) + id____ = 0x00000000, // Found when loading buggy MPT samples + + // Identifiers in "LIST" chunk + idINAM = 0x4D414E49, // "INAM" + idISFT = 0x54465349, // "ISFT" + }; + + typedef ChunkIdentifiers id_type; + + uint32 id; // See ChunkIdentifiers + uint32 length; // Chunk size without header + + size_t GetLength() const + { + uint32 l = length; + return SwapBytesLE(l); + } + + ChunkIdentifiers GetID() const + { + uint32 i = id; + return static_cast<ChunkIdentifiers>(SwapBytesLE(i)); + } +}; + + +// Format Chunk +struct WAVFormatChunk +{ + // Sample formats + enum SampleFormats + { + fmtPCM = 1, + fmtFloat = 3, + fmtIMA_ADPCM = 17, + fmtExtensible = 0xFFFE, + }; + + uint16 format; // Sample format, see SampleFormats + uint16 numChannels; // Number of audio channels + uint32 sampleRate; // Sample rate in Hz + uint32 byteRate; // Bytes per second (should be freqHz * blockAlign) + uint16 blockAlign; // Size of a sample, in bytes (do not trust this value, it's incorrect in some files) + uint16 bitsPerSample; // Bits per sample + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(format); + SwapBytesLE(numChannels); + SwapBytesLE(sampleRate); + SwapBytesLE(byteRate); + SwapBytesLE(blockAlign); + SwapBytesLE(bitsPerSample); + } +}; + + +// Extension of the WAVFormatChunk structure, used if format == formatExtensible +struct WAVFormatChunkExtension +{ + uint16 size; + uint16 validBitsPerSample; + uint32 channelMask; + uint16 subFormat; + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(size); + SwapBytesLE(validBitsPerSample); + SwapBytesLE(channelMask); + SwapBytesLE(subFormat); + } +}; + + +// Sample information chunk +struct WAVSampleInfoChunk +{ + uint32 manufacturer; + uint32 product; + uint32 samplePeriod; // 1000000000 / sampleRate + uint32 baseNote; // 3Ch = C-4 -> 60 + RelativeTone + uint32 pitchFraction; + uint32 SMPTEFormat; + uint32 SMPTEOffset; + uint32 numLoops; // number of loops + uint32 samplerData; + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(manufacturer); + SwapBytesLE(product); + SwapBytesLE(samplePeriod); + SwapBytesLE(baseNote); + SwapBytesLE(pitchFraction); + SwapBytesLE(SMPTEFormat); + SwapBytesLE(SMPTEOffset); + SwapBytesLE(numLoops); + SwapBytesLE(samplerData); + } +}; + + +// Sample loop information chunk (found after WAVSampleInfoChunk in "smpl" chunk) +struct WAVSampleLoop +{ + // Sample Loop Types + enum LoopType + { + loopForward = 0, + loopBidi = 1, + loopBackward = 2, + }; + + uint32 identifier; + uint32 loopType; // See LoopType + uint32 loopStart; // Loop start in samples + uint32 loopEnd; // Loop end in samples + uint32 fraction; + uint32 playCount; // Loop Count, 0 = infinite + + // Convert all... [truncated message content] |
From: <sag...@us...> - 2012-05-28 23:16:06
|
Revision: 1288 http://modplug.svn.sourceforge.net/modplug/?rev=1288&view=rev Author: saga-games Date: 2012-05-28 23:15:59 +0000 (Mon, 28 May 2012) Log Message: ----------- [Mod] Random filter variation settings are not supported anymore when editing IT files. Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/ModConvert.h trunk/OpenMPT/soundlib/ModInstrument.cpp Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-05-27 15:52:58 UTC (rev 1287) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-05-28 23:15:59 UTC (rev 1288) @@ -1172,10 +1172,10 @@ m_EditName.SetLimitText(specs->instrNameLengthMax); m_EditFileName.SetLimitText(specs->instrFilenameLengthMax); - const BOOL bITandMPT = ((m_pSndFile->m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (m_pSndFile->GetNumInstruments())) ? TRUE : FALSE; + const BOOL bITandMPT = ((m_pSndFile->GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (m_pSndFile->GetNumInstruments())) ? TRUE : FALSE; //rewbs.instroVSTi - const BOOL bITandXM = ((m_pSndFile->m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)) && (m_pSndFile->GetNumInstruments())) ? TRUE : FALSE; - const BOOL bMPTOnly = ((m_pSndFile->m_nType == MOD_TYPE_MPT) && (m_pSndFile->GetNumInstruments())) ? TRUE : FALSE; + const BOOL bITandXM = ((m_pSndFile->GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)) && (m_pSndFile->GetNumInstruments())) ? TRUE : FALSE; + const BOOL bMPTOnly = ((m_pSndFile->GetType() == MOD_TYPE_MPT) && (m_pSndFile->GetNumInstruments())) ? TRUE : FALSE; ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT10), bITandXM); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT11), bITandXM); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT7), bITandXM); @@ -1189,13 +1189,13 @@ m_SpinMidiBK.EnableWindow(bITandXM); //rewbs.MidiBank //end rewbs.instroVSTi - const bool extendedFadeoutRange = (m_pSndFile->m_nType & MOD_TYPE_XM) != 0; + const bool extendedFadeoutRange = (m_pSndFile->GetType() & MOD_TYPE_XM) != 0; m_SpinFadeOut.EnableWindow(bITandXM); m_SpinFadeOut.SetRange(0, extendedFadeoutRange ? 32767 : 8192); m_EditFadeOut.SetLimitText(extendedFadeoutRange ? 5 : 4); // Panning ranges (0...64 for IT, 0...256 for MPTM) - m_SpinPanning.SetRange(0, (m_pModDoc->GetModType() & MOD_TYPE_IT) ? 64 : 256); + m_SpinPanning.SetRange(0, (m_pSndFile->GetType() & MOD_TYPE_IT) ? 64 : 256); m_NoteMap.EnableWindow(bITandXM); m_CbnResampling.EnableWindow(bITandXM); @@ -1203,8 +1203,8 @@ m_ComboNNA.EnableWindow(bITandMPT); m_SliderVolSwing.EnableWindow(bITandMPT); m_SliderPanSwing.EnableWindow(bITandMPT); - m_SliderCutSwing.EnableWindow(bITandMPT); - m_SliderResSwing.EnableWindow(bITandMPT); + m_SliderCutSwing.EnableWindow((m_pSndFile->GetType() == MOD_TYPE_MPT || pIns->nCutSwing != 0) ? TRUE : FALSE); + m_SliderResSwing.EnableWindow((m_pSndFile->GetType() == MOD_TYPE_MPT || pIns->nResSwing != 0) ? TRUE : FALSE); m_CbnFilterMode.EnableWindow(bITandMPT); m_ComboDCT.EnableWindow(bITandMPT); m_ComboDCA.EnableWindow(bITandMPT); @@ -1707,20 +1707,21 @@ void CCtrlInstruments::OnInstrumentDuplicate() //-------------------------------------------- { - if (m_pModDoc) + if(m_pModDoc) { CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); - if(pSndFile->m_nInstruments > 0) + if(pSndFile->GetNumInstruments() > 0) { - BOOL bFirst = (pSndFile->m_nInstruments) ? FALSE : TRUE; - LONG ins = m_pModDoc->InsertInstrument(INSTRUMENTINDEX_INVALID, m_nInstrument); - if (ins != INSTRUMENTINDEX_INVALID) + INSTRUMENTINDEX ins = m_pModDoc->InsertInstrument(INSTRUMENTINDEX_INVALID, m_nInstrument); + if(ins != INSTRUMENTINDEX_INVALID) { SetCurrentInstrument(ins); m_pModDoc->UpdateAllViews(NULL, (ins << HINT_SHIFT_INS) | HINT_INSTRUMENT | HINT_INSNAMES | HINT_ENVELOPE); } - if (bFirst) m_pModDoc->UpdateAllViews(NULL, (ins << HINT_SHIFT_INS) | HINT_MODTYPE | HINT_INSTRUMENT | HINT_INSNAMES); - if (m_pParent) m_pParent->InstrumentChanged(m_nInstrument); + if(m_pParent) + { + m_pParent->InstrumentChanged(m_nInstrument); + } } } SwitchToView(); @@ -1751,7 +1752,7 @@ //new instrument if necessary. if(counter > 0) { - if(m_nInstrument >= MAX_INSTRUMENTS-1) + if(m_nInstrument >= MAX_INSTRUMENTS - 1) break; else m_nInstrument++; @@ -1998,7 +1999,7 @@ { if (pIns->nNNA != m_ComboNNA.GetCurSel()) { - pIns->nNNA = m_ComboNNA.GetCurSel(); + pIns->nNNA = m_ComboNNA.GetCurSel(); SetInstrumentModified(true); } } @@ -2042,7 +2043,7 @@ if ((!IsLocked()) && (pIns)) { int n = GetDlgItemInt(IDC_EDIT10); - if ((n >= 0) && (n <= 255)) + if ((n >= 0) && (n <= 128)) { if (pIns->nMidiProgram != n) { @@ -2267,7 +2268,7 @@ if ((!IsLocked()) && (pIns)) { int n = m_ComboPPC.GetCurSel(); - if ((n >= 0) && (n <= NOTE_MAX - 1)) + if(n >= 0 && n <= NOTE_MAX - NOTE_MIN) { if (pIns->nPPC != n) { @@ -2291,7 +2292,7 @@ if (pIns) { pIns->SetCutoff(pIns->GetCutoff(), bCutOff); - for (UINT i=0; i<MAX_CHANNELS; i++) + for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) { if (pSndFile->Chn[i].pModInstrument == pIns) { @@ -2324,7 +2325,7 @@ if (pIns) { pIns->SetResonance(pIns->GetResonance(), bReso); - for (UINT i=0; i<MAX_CHANNELS; i++) + for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) { if (pSndFile->Chn[i].pModInstrument == pIns) { @@ -2363,21 +2364,10 @@ pIns->nFilterMode = instFiltermode; m_pModDoc->SetModified(); - // Translate from mode as stored in instrument to mode as understood by player. - // (The reason for the translation is that the player treats 0 as lowpass, - // but we need to keep 0 as "do not change", so that the instrument setting doesn't - // override the channel setting by default.) - /*int playerFilterMode=-1; - switch (instFilterMode) { - case INST_FILTERMODE_DEFAULT: playerFilterMode = FLTMODE_UNCHANGED;break; - case INST_FILTERMODE_HIGHPASS: playerFilterMode = FLTMODE_HIGHPASS; break; - case INST_FILTERMODE_LOWPASS: playerFilterMode = FLTMODE_LOWPASS; break; - }*/ - - //Update channel settings where this instrument is active, if required. + //Update channel settings where this instrument is active, if required. if(instFiltermode != FLTMODE_UNCHANGED) { - for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) { if (pSndFile->Chn[i].pModInstrument == pIns) pSndFile->Chn[i].nFilterMode = instFiltermode; Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2012-05-27 15:52:58 UTC (rev 1287) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2012-05-28 23:15:59 UTC (rev 1288) @@ -369,7 +369,7 @@ } - // Convert MPT to anything - remove instrument tunings, Pitch/Tempo Lock + // Convert MPT to anything - remove instrument tunings, Pitch/Tempo Lock, filter variation if(oldTypeIsMPT) { if(pIns->pTuning != nullptr) @@ -381,6 +381,11 @@ { CHANGEMODTYPE_WARNING(wPitchToTempoLock); } + + if((pIns->nCutSwing | pIns->nResSwing) != 0) + { + CHANGEMODTYPE_WARNING(wFilterVariation); + } } pIns->Convert(nOldType, nNewType); @@ -534,6 +539,7 @@ CHANGEMODTYPE_CHECK(wPitchToTempoLock, "Pitch / Tempo Lock instrument property is not supported by the new format.\n"); CHANGEMODTYPE_CHECK(wBrokenNoteMap, "Instrument Note Mapping is not supported by the new format.\n"); CHANGEMODTYPE_CHECK(wReleaseNode, "Instrument envelope release nodes are not supported by the new format.\n"); + CHANGEMODTYPE_CHECK(wFilterVariation, "Random filter variation is not supported by the new format.\n"); // General warnings CHANGEMODTYPE_CHECK(wMODGlobalVars, "Default speed, tempo and global volume will be lost.\n"); Modified: trunk/OpenMPT/mptrack/ModConvert.h =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.h 2012-05-27 15:52:58 UTC (rev 1287) +++ trunk/OpenMPT/mptrack/ModConvert.h 2012-05-28 23:15:59 UTC (rev 1288) @@ -36,5 +36,6 @@ wCompatibilityMode, wPitchToTempoLock, wGlobalVolumeNotSupported, + wFilterVariation, wNumWarnings }; Modified: trunk/OpenMPT/soundlib/ModInstrument.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModInstrument.cpp 2012-05-27 15:52:58 UTC (rev 1287) +++ trunk/OpenMPT/soundlib/ModInstrument.cpp 2012-05-28 23:15:59 UTC (rev 1288) @@ -217,5 +217,6 @@ { SetTuning(nullptr); wPitchToTempoLock = 0; + nCutSwing = nResSwing = 0; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-05-29 13:51:18
|
Revision: 1289 http://modplug.svn.sourceforge.net/modplug/?rev=1289&view=rev Author: saga-games Date: 2012-05-29 13:51:08 +0000 (Tue, 29 May 2012) Log Message: ----------- [Fix] WAV loading: Some bugs in loop import. [Imp] Sample Editor: If zooming the current selection is impossible, the zoom context menu item is greyed out. [Imp] VST: If supported by the plugin, effGetParameterProperties is used to retrieve parameter names. [Ref] Smaller changes. [Mod] OpenMPT: Version is now 1.20.01.05 Modified Paths: -------------- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp trunk/OpenMPT/mptrack/AbstractVstEditor.h trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/mptrack/View_smp.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/MIDIEvents.cpp trunk/OpenMPT/soundlib/MIDIEvents.h trunk/OpenMPT/soundlib/SampleFormatConverters.h trunk/OpenMPT/soundlib/WAVTools.cpp Modified: trunk/OpenMPT/mptrack/AbstractVstEditor.cpp =================================================================== --- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2012-05-29 13:51:08 UTC (rev 1289) @@ -247,7 +247,7 @@ //end rewbs.defaultPlugGUI BOOL CAbstractVstEditor::PreTranslateMessage(MSG* pMsg) -//---------------------------------------------------- +//----------------------------------------------------- { if (pMsg) { @@ -273,7 +273,7 @@ } // Don't forward key repeats if plug does not listen for keypresses - // (avoids system beeps on note hold) + // (avoids system beeps on note hold) if (kT == kKeyEventRepeat) { return true; @@ -285,7 +285,7 @@ } -void CAbstractVstEditor::SetTitle() +void CAbstractVstEditor::SetTitle() //--------------------------------- { if (m_pVstPlugin && m_pVstPlugin->m_pMixStruct) @@ -355,7 +355,7 @@ m_nInstrument = GetBestInstrumentCandidate(); //only show messagebox if plug is able to process notes. - if(m_nInstrument < 0) + if(m_nInstrument == INSTRUMENTINDEX_INVALID) { if(m_pVstPlugin->CanRecieveMidiEvents()) { @@ -512,16 +512,15 @@ CArray<UINT, UINT> inputInstruments; m_pVstPlugin->GetInputInstrumentList(inputInstruments); - bool checked; - for (int nIns=0; nIns<inputInstruments.GetSize(); nIns++) + for(int nIns = 0; nIns<inputInstruments.GetSize(); nIns++) { - checked=false; + bool checked = false; if (nIns==0 && (inputPlugs.GetSize() || inputChannels.GetSize())) { m_pInputMenu->AppendMenu(MF_SEPARATOR); } name.Format("Ins%02d: %s", inputInstruments[nIns], (LPCTSTR)pSndFile->GetInstrumentName(inputInstruments[nIns])); - if (inputInstruments[nIns] == (UINT)m_nInstrument) checked=true; + if (inputInstruments[nIns] == (UINT)m_nInstrument) checked = true; m_pInputMenu->AppendMenu(MF_STRING|(checked?MF_CHECKED:0), ID_SELECTINST+inputInstruments[nIns], name); } @@ -673,21 +672,21 @@ } -bool CAbstractVstEditor::CheckInstrument(int instrument) -//------------------------------------------------------ +bool CAbstractVstEditor::CheckInstrument(INSTRUMENTINDEX ins) +//----------------------------------------------------------- { CSoundFile* pSndFile = m_pVstPlugin->GetSoundFile(); - if (instrument >= 0 && instrument<MAX_INSTRUMENTS && pSndFile->Instruments[instrument]) + if(ins != INSTRUMENTINDEX_INVALID && ins < MAX_INSTRUMENTS && pSndFile->Instruments[ins] != nullptr) { - return (pSndFile->Instruments[instrument]->nMixPlug) == (m_pVstPlugin->m_nSlot + 1); + return (pSndFile->Instruments[ins]->nMixPlug) == (m_pVstPlugin->m_nSlot + 1); } return false; } -int CAbstractVstEditor::GetBestInstrumentCandidate() -//-------------------------------------------------- +INSTRUMENTINDEX CAbstractVstEditor::GetBestInstrumentCandidate() +//-------------------------------------------------------------- { //First try current instrument: /* CModDoc* pModDoc = m_pVstPlugin->GetModDoc(); @@ -699,20 +698,20 @@ //Then just take the first instrument that points to this plug.. CArray<UINT, UINT> plugInstrumentList; m_pVstPlugin->GetInputInstrumentList(plugInstrumentList); - if (plugInstrumentList.GetSize()) + if(plugInstrumentList.GetSize()) { - return plugInstrumentList[0]; + return static_cast<INSTRUMENTINDEX>(plugInstrumentList[0]); } //No instrument in the entire track points to this plug. - return -1; + return INSTRUMENTINDEX_INVALID; } void CAbstractVstEditor::OnSetInputInstrument(UINT nID) //----------------------------------------------------- { - m_nInstrument = (nID - ID_SELECTINST); + m_nInstrument = static_cast<INSTRUMENTINDEX>(nID - ID_SELECTINST); } Modified: trunk/OpenMPT/mptrack/AbstractVstEditor.h =================================================================== --- trunk/OpenMPT/mptrack/AbstractVstEditor.h 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/mptrack/AbstractVstEditor.h 2012-05-29 13:51:08 UTC (rev 1289) @@ -77,10 +77,10 @@ void UpdateOutputMenu(); void UpdateMacroMenu(); void UpdateOptionsMenu(); - int GetBestInstrumentCandidate(); - bool CheckInstrument(int instrument); + INSTRUMENTINDEX GetBestInstrumentCandidate(); + bool CheckInstrument(INSTRUMENTINDEX ins); bool ValidateCurrentInstrument(); - int m_nInstrument; + INSTRUMENTINDEX m_nInstrument; int m_nLearnMacro; void OnToggleEditor(UINT nID); Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2012-05-29 13:51:08 UTC (rev 1289) @@ -1489,9 +1489,9 @@ { if (m_dwEndSel >= m_dwBeginSel + 4) { - ::AppendMenu(hMenu, MF_STRING, ID_SAMPLE_ZOOMONSEL, "Zoom"); + ::AppendMenu(hMenu, MF_STRING | (CanZoomSelection() ? 0 : MF_GRAYED), ID_SAMPLE_ZOOMONSEL, "Zoom"); ::AppendMenu(hMenu, MF_STRING, ID_SAMPLE_SETLOOP, "Set As Loop"); - if (pSndFile->m_nType & (MOD_TYPE_IT|MOD_TYPE_MPT)) + if (pSndFile->GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) ::AppendMenu(hMenu, MF_STRING, ID_SAMPLE_SETSUSTAINLOOP, "Set As Sustain Loop"); ::AppendMenu(hMenu, MF_SEPARATOR, 0, ""); } else @@ -1502,21 +1502,22 @@ { //Set loop points wsprintf(s, "Set Loop Start to:\t%d", dwPos); - ::AppendMenu(hMenu, MF_STRING|((dwPos+4<=sample.nLoopEnd)?0:MF_GRAYED), - ID_SAMPLE_SETLOOPSTART, s); + ::AppendMenu(hMenu, MF_STRING | (dwPos + 4 <= sample.nLoopEnd ? 0 : MF_GRAYED), + ID_SAMPLE_SETLOOPSTART, s); wsprintf(s, "Set Loop End to:\t%d", dwPos); - ::AppendMenu(hMenu, MF_STRING|((dwPos>=sample.nLoopStart+4)?0:MF_GRAYED), - ID_SAMPLE_SETLOOPEND, s); + ::AppendMenu(hMenu, MF_STRING | (dwPos >= sample.nLoopStart + 4 ? 0 : MF_GRAYED), + ID_SAMPLE_SETLOOPEND, s); - if (pSndFile->m_nType & (MOD_TYPE_IT|MOD_TYPE_MPT)) { + if (pSndFile->GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) + { //Set sustain loop points ::AppendMenu(hMenu, MF_SEPARATOR, 0, ""); wsprintf(s, "Set Sustain Start to:\t%d", dwPos); - ::AppendMenu(hMenu, MF_STRING|((dwPos+4<=sample.nSustainEnd)?0:MF_GRAYED), - ID_SAMPLE_SETSUSTAINSTART, s); + ::AppendMenu(hMenu, MF_STRING | (dwPos + 4 <= sample.nSustainEnd ? 0 : MF_GRAYED), + ID_SAMPLE_SETSUSTAINSTART, s); wsprintf(s, "Set Sustain End to:\t%d", dwPos); - ::AppendMenu(hMenu, MF_STRING|((dwPos>=sample.nSustainStart+4)?0:MF_GRAYED), - ID_SAMPLE_SETSUSTAINEND, s); + ::AppendMenu(hMenu, MF_STRING | (dwPos >= sample.nSustainStart + 4 ? 0 : MF_GRAYED), + ID_SAMPLE_SETSUSTAINEND, s); } ::AppendMenu(hMenu, MF_SEPARATOR, 0, ""); m_dwMenuParam = dwPos; @@ -2363,15 +2364,28 @@ } +UINT CViewSample::GetSelectionZoomLevel() const +//--------------------------------------------- +{ + UINT zoom = 0; + while(((static_cast<UINT>(m_rcClient.right) << zoom) < m_dwEndSel - m_dwBeginSel) && (zoom < MAX_ZOOM - 1)) + { + zoom++; + } + if(zoom++ < MAX_ZOOM) + return zoom; + else + return 0; +} + + void CViewSample::OnZoomOnSel() //----------------------------- { if ((m_dwEndSel > m_dwBeginSel) && (m_rcClient.right > 0)) { - DWORD dwZoom = 0; - - while ((((DWORD)m_rcClient.right << dwZoom) < (m_dwEndSel - m_dwBeginSel)) && (dwZoom < (MAX_ZOOM-1))) dwZoom++; - if (dwZoom < (MAX_ZOOM-1)) dwZoom++; else dwZoom = 0; + DWORD dwZoom = GetSelectionZoomLevel(); + SendCtrlMessage(CTRLMSG_SMP_SETZOOM, dwZoom); if (dwZoom) { @@ -2575,9 +2589,12 @@ if (!pSndFile) return 0; const BYTE nNote = midibyte1 + NOTE_MIN; - int nVol = midibyte2; - BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiData); - if ((event == MIDIEvents::evNoteOn) && !nVol) event = MIDIEvents::evNoteOff; //Convert event to note-off if req'd + int nVol = midibyte2; + MIDIEvents::EventType event = MIDIEvents::GetTypeFromEvent(dwMidiData); + if(event == MIDIEvents::evNoteOn && !nVol) + { + event = MIDIEvents::evNoteOff; //Convert event to note-off if req'd + } // Handle MIDI messages assigned to shortcuts CInputHandler *ih = CMainFrame::GetMainFrame()->GetInputHandler(); @@ -2709,7 +2726,7 @@ // return value is N. If zoom is bigger than the biggest zoom, returns MIN_ZOOM + 1 and // if smaller than the smallest zoom, returns value >= MAX_ZOOM + 1. UINT CViewSample::GetAutoZoomLevel(const ModSample& smp) -//----------------------------------------------------- +//------------------------------------------------------ { m_rcClient.NormalizeRect(); if (m_rcClient.Width() == 0 || smp.nLength <= 0) Modified: trunk/OpenMPT/mptrack/View_smp.h =================================================================== --- trunk/OpenMPT/mptrack/View_smp.h 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/mptrack/View_smp.h 2012-05-29 13:51:08 UTC (rev 1289) @@ -60,22 +60,26 @@ // Sets sample data on sample draw. template<class T, class uT> - void SetSampleData(void* pSample, const CPoint& point, const DWORD old); + void SetSampleData(void *pSample, const CPoint &point, const DWORD old); // Sets initial draw point on sample draw. template<class T, class uT> - void SetInitialDrawPoint(void* pSample, const CPoint& point); + void SetInitialDrawPoint(void *pSample, const CPoint &point); // Returns sample value corresponding given point in the sample view. template<class T, class uT> - T GetSampleValueFromPoint(const CPoint& point); + T GetSampleValueFromPoint(const CPoint &point); // Returns auto-zoom level compared to other zoom levels. // If auto-zoom gives bigger zoom than zoom level N but smaller than zoom level N-1, // return value is N. If zoom is bigger than the biggest zoom, returns MIN_ZOOM + 1 and // if smaller than the smallest zoom, returns value >= MAX_ZOOM + 1. - UINT GetAutoZoomLevel(const ModSample& smp); + UINT GetAutoZoomLevel(const ModSample &smp); + // Calculate zoom level based on the current selection + UINT GetSelectionZoomLevel() const; + bool CanZoomSelection() const { return GetSelectionZoomLevel() != 0; } + UINT ScrollPosToSamplePos() const {return ScrollPosToSamplePos(m_nZoom);} UINT ScrollPosToSamplePos(UINT nZoom) const {return (nZoom > 0) ? (m_nScrollPos << (nZoom - 1)) : 0;} Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-05-29 13:51:08 UTC (rev 1289) @@ -1850,7 +1850,19 @@ CString CVstPlugin::GetFormattedParamName(PlugParamIndex param) //------------------------------------------------------------- { - const CString paramName = GetParamName(param); + static VstParameterProperties properties; + + CString paramName; + + if(Dispatch(effGetParameterProperties, param, nullptr, &properties, 0.0f) == 1) + { + StringFixer::SetNullTerminator(properties.label); + paramName = properties.label; + } else + { + paramName = GetParamName(param); + } + CString name; if(paramName.IsEmpty()) { Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/mptrack/version.h 2012-05-29 13:51:08 UTC (rev 1289) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 04 +#define VER_MINORMINOR 05 //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/MIDIEvents.cpp =================================================================== --- trunk/OpenMPT/soundlib/MIDIEvents.cpp 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/soundlib/MIDIEvents.cpp 2012-05-29 13:51:08 UTC (rev 1289) @@ -1,6 +1,6 @@ /* - * MIDI.cpp - * -------- + * MIDIEvents.cpp + * -------------- * Purpose: MIDI event handling, event lists, ... * Notes : (currently none) * Authors: OpenMPT Devs @@ -26,7 +26,7 @@ uint32 BuildCCEvent(MidiCC midiCC, uint8 midiChannel, uint8 param) //---------------------------------------------------------------- { - return BuildEvent(evControllerChange, midiChannel, midiCC, param); + return BuildEvent(evControllerChange, midiChannel, static_cast<uint8>(midiCC), param); } @@ -34,7 +34,7 @@ uint32 BuildPitchBendEvent(uint8 midiChannel, uint16 bendAmount) //-------------------------------------------------------------- { - return BuildEvent(evPitchBend, midiChannel, (bendAmount & 0x7F), (bendAmount >> 7)); + return BuildEvent(evPitchBend, midiChannel, static_cast<uint8>(bendAmount & 0x7F), static_cast<uint8>(bendAmount >> 7)); } @@ -66,7 +66,7 @@ uint8 BuildSystemEvent(SystemEvent eventType) //------------------------------------------- { - return (evSystem << 4) | eventType; + return static_cast<uint8>((evSystem << 4) | eventType); } Modified: trunk/OpenMPT/soundlib/MIDIEvents.h =================================================================== --- trunk/OpenMPT/soundlib/MIDIEvents.h 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/soundlib/MIDIEvents.h 2012-05-29 13:51:08 UTC (rev 1289) @@ -1,6 +1,6 @@ /* - * MIDI.h - * ------ + * MIDIEvents.h + * ------------ * Purpose: MIDI event handling, event lists, ... * Notes : (currently none) * Authors: OpenMPT Devs Modified: trunk/OpenMPT/soundlib/SampleFormatConverters.h =================================================================== --- trunk/OpenMPT/soundlib/SampleFormatConverters.h 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/soundlib/SampleFormatConverters.h 2012-05-29 13:51:08 UTC (rev 1289) @@ -430,5 +430,5 @@ } } - return numSamples * sizeof(SampleConversion::input_t) * sample.GetNumChannels(); + return numSamples * inSize; } Modified: trunk/OpenMPT/soundlib/WAVTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.cpp 2012-05-28 23:15:59 UTC (rev 1288) +++ trunk/OpenMPT/soundlib/WAVTools.cpp 2012-05-29 13:51:08 UTC (rev 1289) @@ -131,7 +131,7 @@ // Read software name const bool isOldMPT = infoChunk.GetChunk(RIFFChunk::idISFT).ReadMagic("Modplug Tracker"); - sample.uFlags &= ~(CHN_LOOP | CHN_SUSTAINLOOP); + sample.uFlags &= ~(CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); // Convert loops if(!sampleLoops.empty()) @@ -139,7 +139,7 @@ size_t normalLoopIndex = 0; if(sampleLoops.size() > 1) { - sampleLoops[0].ApplyToSample(sample.nSustainStart, sample.nSustainStart, sample.nLength, sample.uFlags, CHN_SUSTAINLOOP, CHN_PINGPONGSUSTAIN, isOldMPT); + sampleLoops[0].ApplyToSample(sample.nSustainStart, sample.nSustainEnd, sample.nLength, sample.uFlags, CHN_SUSTAINLOOP, CHN_PINGPONGSUSTAIN, isOldMPT); normalLoopIndex = 1; } sampleLoops[normalLoopIndex].ApplyToSample(sample.nLoopStart, sample.nLoopEnd, sample.nLength, sample.uFlags, CHN_LOOP, CHN_PINGPONGLOOP, isOldMPT); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-07 13:55:45
|
Revision: 1292 http://modplug.svn.sourceforge.net/modplug/?rev=1292&view=rev Author: saga-games Date: 2012-06-07 13:55:37 +0000 (Thu, 07 Jun 2012) Log Message: ----------- [Ref] Got rid of ModDoc stuff in pattern implementation. [Ref] Other small changes. Modified Paths: -------------- trunk/OpenMPT/mptrack/CommandSet.cpp trunk/OpenMPT/mptrack/CommandSet.h trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp trunk/OpenMPT/mptrack/Undo.cpp trunk/OpenMPT/mptrack/Undo.h trunk/OpenMPT/soundlib/ModSequence.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/pattern.cpp trunk/OpenMPT/soundlib/pattern.h Modified: trunk/OpenMPT/mptrack/CommandSet.cpp =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/CommandSet.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -1266,14 +1266,12 @@ } if (enforceRule[krCheckModifiers]) { - const int nForcedModifiers = 4; - CommandID forcedModifiers[nForcedModifiers] = {kcSelect, kcCopySelect, kcChordModifier, kcSetSpacing}; - CommandID curCmd; + static const CommandID forcedModifiers[] = { kcSelect, kcCopySelect, kcChordModifier, kcSetSpacing }; // for all commands that must be modifiers - for (int i=0; i<nForcedModifiers; i++) + for (int i = 0; i < CountOf(forcedModifiers); i++) { - curCmd=forcedModifiers[i]; + CommandID curCmd = forcedModifiers[i]; //for all of this command's key combinations for (int k=0; k<commands[curCmd].kcList.GetSize(); k++) @@ -1282,7 +1280,7 @@ if ((!curKc.mod) || (curKc.code!=VK_SHIFT && curKc.code!=VK_CONTROL && curKc.code!=VK_MENU && curKc.code!=0 && curKc.code!=VK_LWIN && curKc.code!=VK_RWIN )) // Feature: use Windows keys as modifier keys { - report+="Error! " + GetCommandText((CommandID)curCmd) + " must be a modifier (shift/ctrl/alt), but is currently " + GetKeyText(inKc.mod, inKc.code) + "\r\n"; + report += ("Error! " + GetCommandText((CommandID)curCmd) + " must be a modifier (shift/ctrl/alt), but is currently " + GetKeyText(inKc.mod, inKc.code) + "\r\n"); //replace with dummy commands[curCmd].kcList[k].mod=1; commands[curCmd].kcList[k].code=0; @@ -1369,7 +1367,7 @@ //Clear map memset(km, -1, sizeof(KeyMap)); - //Copy commandlist content into map: + //Copy commandlist content into map: for (UINT cmd=0; cmd<kcNumCommands; cmd++) { if (IsDummyCommand((CommandID)cmd)) @@ -1491,9 +1489,9 @@ return false; } fprintf(outStream, "//-------- OpenMPT key binding definition file -------\n"); - fprintf(outStream, "//-Format is: -\n"); - fprintf(outStream, "//- Context:Command ID:Modifiers:Key:KeypressEventType //Comments -\n"); - fprintf(outStream, "//----------------------------------------------------------------------\n"); + fprintf(outStream, "//-Format is: -\n"); + fprintf(outStream, "//- Context:Command ID:Modifiers:Key:KeypressEventType //Comments -\n"); + fprintf(outStream, "//----------------------------------------------------------------------\n"); fprintf(outStream, "version:%u\n", KEYMAP_VERSION); for (int ctx=0; ctx<kCtxMaxInputContexts; ctx++) @@ -1545,7 +1543,6 @@ while(iStrm.getline(s, sizeof(s))) { - //Reporting::Notification(s, MB_ICONEXCLAMATION|MB_OK); curLine = s; Modified: trunk/OpenMPT/mptrack/CommandSet.h =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.h 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/CommandSet.h 2012-06-07 13:55:37 UTC (rev 1292) @@ -17,7 +17,7 @@ #define KEYMAP_VERSION 1 // Version of the .mkb format -#define HOTKEYF_MIDI 0x10 +#define HOTKEYF_MIDI 0x10 // modifier mask for MIDI CCs enum InputTargetContext { Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -141,7 +141,7 @@ { m_SndFile.TryWriteEffect(nPat, m_SndFile.Patterns[nPat].GetNumRows() - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weTryNextRow); } - m_SndFile.Patterns[nPat].Resize(64, false); + m_SndFile.Patterns[nPat].Resize(64); CHANGEMODTYPE_WARNING(wResizedPatterns); } Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -1029,9 +1029,9 @@ { IMixPlugin *pPlugin = m_SndFile.m_MixPlugins[nPlugin - 1].pMixPlugin; - if (pPlugin) + if(pPlugin != nullptr) { - pPlugin->MidiCommand(GetPlaybackMidiChannel(pIns, nCurrentChn), pIns->nMidiProgram, pIns->wMidiBank, pIns->NoteMap[note - 1], pChn->nVolume, MAX_BASECHANNELS); + pPlugin->MidiCommand(GetPlaybackMidiChannel(pIns, nCurrentChn), pIns->nMidiProgram, pIns->wMidiBank, pIns->NoteMap[note - 1], static_cast<uint16>(pChn->nVolume), MAX_BASECHANNELS); } } } Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -684,25 +684,56 @@ BOOL CModDoc::ExpandPattern(PATTERNINDEX nPattern) //------------------------------------------------ { -// -> CODE#0008 -// -> DESC="#define to set pattern size" + ROWINDEX numRows; - if ((nPattern >= m_SndFile.Patterns.Size()) || (!m_SndFile.Patterns[nPattern])) return FALSE; - if(m_SndFile.Patterns[nPattern].Expand()) - return FALSE; - else - return TRUE; + if(!m_SndFile.Patterns.IsValidPat(nPattern) + || (numRows = m_SndFile.Patterns[nPattern].GetNumRows()) > m_SndFile.GetModSpecifications().patternRowsMax / 2) + { + return false; + } + + BeginWaitCursor(); + GetPatternUndo().PrepareUndo(nPattern, 0, 0, GetNumChannels(), numRows); + bool success = m_SndFile.Patterns[nPattern].Expand(); + EndWaitCursor(); + + if(success) + { + SetModified(); + UpdateAllViews(NULL, HINT_PATTERNDATA | (nPattern << HINT_SHIFT_PAT), NULL); + } else + { + GetPatternUndo().RemoveLastUndoStep(); + } + return success; } BOOL CModDoc::ShrinkPattern(PATTERNINDEX nPattern) //------------------------------------------------ { - if ((nPattern >= m_SndFile.Patterns.Size()) || (!m_SndFile.Patterns[nPattern])) return FALSE; - if(m_SndFile.Patterns[nPattern].Shrink()) - return FALSE; - else - return TRUE; + ROWINDEX numRows; + + if(!m_SndFile.Patterns.IsValidPat(nPattern) + || (numRows = m_SndFile.Patterns[nPattern].GetNumRows()) < m_SndFile.GetModSpecifications().patternRowsMin * 2) + { + return false; + } + + BeginWaitCursor(); + GetPatternUndo().PrepareUndo(nPattern, 0, 0, GetNumChannels(), numRows); + bool success = m_SndFile.Patterns[nPattern].Shrink(); + EndWaitCursor(); + + if(success) + { + SetModified(); + UpdateAllViews(NULL, HINT_PATTERNDATA | (nPattern << HINT_SHIFT_PAT), NULL); + } else + { + GetPatternUndo().RemoveLastUndoStep(); + } + return success; } Modified: trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -578,8 +578,31 @@ } const ROWINDEX newSize = (ROWINDEX)GetDlgItemInt(IDC_COMBO1, NULL, FALSE); - m_pModDoc->GetPatternUndo().PrepareUndo(m_nPattern, 0, newSize, pSndFile->Patterns[m_nPattern].GetNumChannels(), pSndFile->Patterns[m_nPattern].GetNumRows() - newSize); - pSndFile->Patterns[m_nPattern].Resize(newSize); + + // Check if any pattern data would be removed. + bool resize = true; + if(newSize < pSndFile->Patterns[m_nPattern].GetNumRows()) + { + for(ROWINDEX row = newSize; row < pSndFile->Patterns[m_nPattern].GetNumRows(); row++) + { + if(!pSndFile->Patterns[m_nPattern].IsEmptyRow(row)) + { + resize = (Reporting::Confirm("Data at the end of the pattern will be lost.\nDo you want to continue?", "Shrink Pattern") == cnfYes); + break; + } + } + } + + if(resize) + { + m_pModDoc->GetPatternUndo().PrepareUndo(m_nPattern, 0, newSize, pSndFile->Patterns[m_nPattern].GetNumChannels(), pSndFile->Patterns[m_nPattern].GetNumRows() - newSize); + m_pModDoc->BeginWaitCursor(); + if(pSndFile->Patterns[m_nPattern].Resize(newSize)) + { + m_pModDoc->SetModified(); + } + m_pModDoc->EndWaitCursor(); + } } CDialog::OnOK(); } Modified: trunk/OpenMPT/mptrack/Undo.cpp =================================================================== --- trunk/OpenMPT/mptrack/Undo.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/Undo.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -48,7 +48,7 @@ CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); if(pSndFile == nullptr) return false; - PATTERNUNDOBUFFER sUndo; + UndoInfo sUndo; ModCommand *pUndoData, *pPattern; ROWINDEX nRows; @@ -62,7 +62,7 @@ pUndoData = CPattern::AllocatePattern(numRows, numChns); if (!pUndoData) return false; - const bool bUpdate = !CanUndo(); // update undo status? + const bool updateView = !CanUndo(); // update undo status? // Remove an undo step if there are too many. while(UndoBuffer.size() >= MAX_UNDO_LEVEL) @@ -88,9 +88,7 @@ if(storeChannelInfo) { - sUndo.channelInfo = new PATTERNUNDOINFO; - sUndo.channelInfo->oldNumChannels = pSndFile->GetNumChannels(); - sUndo.channelInfo->settings = new ModChannelSettings[pSndFile->GetNumChannels()]; + sUndo.channelInfo = new ChannelInfo(pSndFile->GetNumChannels()); memcpy(sUndo.channelInfo->settings, pSndFile->ChnSettings, sizeof(ModChannelSettings) * pSndFile->GetNumChannels()); } else { @@ -99,7 +97,7 @@ UndoBuffer.push_back(sUndo); - if (bUpdate) m_pModDoc->UpdateAllViews(NULL, HINT_UNDO); + if(updateView) m_pModDoc->UpdateAllViews(NULL, HINT_UNDO); return true; } @@ -138,7 +136,7 @@ } // Select most recent undo slot - const PATTERNUNDOBUFFER *pUndo = &UndoBuffer.back(); + const UndoInfo *pUndo = &UndoBuffer.back(); if(pUndo->channelInfo != nullptr) { @@ -183,7 +181,7 @@ } } else if(pSndFile->Patterns[nPattern].GetNumRows() != nRows) { - pSndFile->Patterns[nPattern].Resize(nRows, false); + pSndFile->Patterns[nPattern].Resize(nRows); } linkToPrevious = pUndo->linkToPrevious; @@ -221,17 +219,16 @@ // Delete a given undo step. -void CPatternUndo::DeleteUndoStep(UINT nStep) -//------------------------------------------- +void CPatternUndo::DeleteUndoStep(size_t step) +//-------------------------------------------- { - if(nStep >= UndoBuffer.size()) return; - if(UndoBuffer[nStep].pbuffer) delete[] UndoBuffer[nStep].pbuffer; - if(UndoBuffer[nStep].channelInfo) + if(step >= UndoBuffer.size()) return; + if(UndoBuffer[step].pbuffer) delete[] UndoBuffer[step].pbuffer; + if(UndoBuffer[step].channelInfo) { - delete[] UndoBuffer[nStep].channelInfo->settings; - delete UndoBuffer[nStep].channelInfo; + delete UndoBuffer[step].channelInfo; } - UndoBuffer.erase(UndoBuffer.begin() + nStep); + UndoBuffer.erase(UndoBuffer.begin() + step); } @@ -252,23 +249,23 @@ void CSampleUndo::ClearUndo() //--------------------------- { - for(SAMPLEINDEX nSmp = 1; nSmp <= MAX_SAMPLES; nSmp++) + for(SAMPLEINDEX smp = 1; smp <= MAX_SAMPLES; smp++) { - ClearUndo(nSmp); + ClearUndo(smp); } UndoBuffer.clear(); } // Remove all undo steps of a given sample. -void CSampleUndo::ClearUndo(const SAMPLEINDEX nSmp) -//------------------------------------------------- +void CSampleUndo::ClearUndo(const SAMPLEINDEX smp) +//------------------------------------------------ { - if(!SampleBufferExists(nSmp, false)) return; + if(!SampleBufferExists(smp, false)) return; - while(UndoBuffer[nSmp - 1].size() > 0) + while(UndoBuffer[smp - 1].size() > 0) { - DeleteUndoStep(nSmp, 0); + DeleteUndoStep(smp, 0); } } @@ -276,49 +273,49 @@ // Create undo point for given sample. // The main program has to tell what kind of changes are going to be made to the sample. // That way, a lot of RAM can be saved, because some actions don't even require an undo sample buffer. -bool CSampleUndo::PrepareUndo(const SAMPLEINDEX nSmp, sampleUndoTypes nChangeType, UINT nChangeStart, UINT nChangeEnd) -//-------------------------------------------------------------------------------------------------------------------- +bool CSampleUndo::PrepareUndo(const SAMPLEINDEX smp, sampleUndoTypes changeType, SmpLength changeStart, SmpLength changeEnd) +//-------------------------------------------------------------------------------------------------------------------------- { - if(m_pModDoc == nullptr || !SampleBufferExists(nSmp)) return false; + if(m_pModDoc == nullptr || !SampleBufferExists(smp)) return false; CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); if(pSndFile == nullptr) return false; // Remove an undo step if there are too many. - while(UndoBuffer[nSmp - 1].size() >= MAX_UNDO_LEVEL) + while(UndoBuffer[smp - 1].size() >= MAX_UNDO_LEVEL) { - DeleteUndoStep(nSmp, 0); + DeleteUndoStep(smp, 0); } // Restrict amount of memory that's being used RestrictBufferSize(); // Create new undo slot - SAMPLEUNDOBUFFER sUndo; + UndoInfo sUndo; - const ModSample &oldsample = pSndFile->GetSample(nSmp); + const ModSample &oldsample = pSndFile->GetSample(smp); // Save old sample header MemCopy(sUndo.OldSample, oldsample); - MemCopy(sUndo.szOldName, pSndFile->m_szNames[nSmp]); - sUndo.nChangeType = nChangeType; + MemCopy(sUndo.szOldName, pSndFile->m_szNames[smp]); + sUndo.nChangeType = changeType; - if(nChangeType == sundo_replace) + if(changeType == sundo_replace) { // ensure that size information is correct here. - nChangeStart = 0; - nChangeEnd = oldsample.nLength; - } else if(nChangeType == sundo_none) + changeStart = 0; + changeEnd = oldsample.nLength; + } else if(changeType == sundo_none) { // we do nothing... - nChangeStart = nChangeEnd = 0; + changeStart = changeEnd = 0; } - sUndo.nChangeStart = nChangeStart; - sUndo.nChangeEnd = nChangeEnd; + sUndo.nChangeStart = changeStart; + sUndo.nChangeEnd = changeEnd; sUndo.SamplePtr = nullptr; - switch(nChangeType) + switch(changeType) { case sundo_none: // we are done, no sample changes here. case sundo_invert: // no action necessary, since those effects can be applied again to be undone. @@ -330,17 +327,18 @@ case sundo_update: case sundo_delete: case sundo_replace: + if(oldsample.pSample != nullptr) { - UINT nBytesPerSample = oldsample.GetBytesPerSample(); - UINT nChangeLen = nChangeEnd - nChangeStart; + size_t nBytesPerSample = oldsample.GetBytesPerSample(); + size_t nChangeLen = changeEnd - changeStart; sUndo.SamplePtr = pSndFile->AllocateSample(nChangeLen * nBytesPerSample + 4 * nBytesPerSample); if(sUndo.SamplePtr == nullptr) return false; - memcpy(sUndo.SamplePtr, oldsample.pSample + nChangeStart * nBytesPerSample, nChangeLen * nBytesPerSample); + memcpy(sUndo.SamplePtr, oldsample.pSample + changeStart * nBytesPerSample, nChangeLen * nBytesPerSample); -#ifdef DEBUG +#ifdef _DEBUG char s[64]; - const UINT nSize = (GetUndoBufferCapacity() + nChangeLen * nBytesPerSample) >> 10; + const size_t nSize = (GetUndoBufferCapacity() + nChangeLen * nBytesPerSample) >> 10; wsprintf(s, "Sample undo buffer size is now %u.%u MB\n", nSize >> 10, (nSize & 1023) * 100 / 1024); Log(s); #endif @@ -353,7 +351,7 @@ return false; } - UndoBuffer[nSmp - 1].push_back(sUndo); + UndoBuffer[smp - 1].push_back(sUndo); m_pModDoc->UpdateAllViews(NULL, HINT_UNDO); @@ -362,18 +360,18 @@ // Restore undo point for given sample -bool CSampleUndo::Undo(const SAMPLEINDEX nSmp) -//-------------------------------------------- +bool CSampleUndo::Undo(const SAMPLEINDEX smp) +//------------------------------------------- { - if(m_pModDoc == nullptr || !CanUndo(nSmp)) return false; + if(m_pModDoc == nullptr || !CanUndo(smp)) return false; CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); if(pSndFile == nullptr) return false; // Select most recent undo slot - SAMPLEUNDOBUFFER &undo = UndoBuffer[nSmp - 1].back(); + UndoInfo &undo = UndoBuffer[smp - 1].back(); - ModSample &sample = pSndFile->GetSample(nSmp); + ModSample &sample = pSndFile->GetSample(smp); LPSTR pCurrentSample = sample.pSample; LPSTR pNewSample = nullptr; // a new sample is possibly going to be allocated, depending on what's going to be undone. @@ -437,7 +435,7 @@ // Restore old sample header sample = undo.OldSample; sample.pSample = pCurrentSample; // select the "correct" old sample - MemCopy(pSndFile->m_szNames[nSmp], undo.szOldName); + MemCopy(pSndFile->m_szNames[smp], undo.szOldName); if(pNewSample != nullptr) { @@ -445,9 +443,9 @@ } ctrlSmp::AdjustEndOfSample(sample, pSndFile); - RemoveLastUndoStep(nSmp); + RemoveLastUndoStep(smp); - if (CanUndo(nSmp) == false) m_pModDoc->UpdateAllViews(NULL, HINT_UNDO); + if (CanUndo(smp) == false) m_pModDoc->UpdateAllViews(NULL, HINT_UNDO); m_pModDoc->SetModified(); return true; @@ -455,30 +453,30 @@ // Check if given sample has a valid undo buffer -bool CSampleUndo::CanUndo(const SAMPLEINDEX nSmp) -//----------------------------------------------- +bool CSampleUndo::CanUndo(const SAMPLEINDEX smp) +//---------------------------------------------- { - if(!SampleBufferExists(nSmp, false) || UndoBuffer[nSmp - 1].size() == 0) return false; + if(!SampleBufferExists(smp, false) || UndoBuffer[smp - 1].size() == 0) return false; return true; } // Delete a given undo step of a sample. -void CSampleUndo::DeleteUndoStep(const SAMPLEINDEX nSmp, const UINT nStep) +void CSampleUndo::DeleteUndoStep(const SAMPLEINDEX smp, const size_t step) //------------------------------------------------------------------------ { - if(!SampleBufferExists(nSmp, false) || nStep >= UndoBuffer[nSmp - 1].size()) return; - CSoundFile::FreeSample(UndoBuffer[nSmp - 1][nStep].SamplePtr); - UndoBuffer[nSmp - 1].erase(UndoBuffer[nSmp - 1].begin() + nStep); + if(!SampleBufferExists(smp, false) || step >= UndoBuffer[smp - 1].size()) return; + CSoundFile::FreeSample(UndoBuffer[smp - 1][step].SamplePtr); + UndoBuffer[smp - 1].erase(UndoBuffer[smp - 1].begin() + step); } // Public helper function to remove the most recent undo point. -void CSampleUndo::RemoveLastUndoStep(const SAMPLEINDEX nSmp) -//---------------------------------------------------------- +void CSampleUndo::RemoveLastUndoStep(const SAMPLEINDEX smp) +//--------------------------------------------------------- { - if(CanUndo(nSmp) == false) return; - DeleteUndoStep(nSmp, UndoBuffer[nSmp - 1].size() - 1); + if(CanUndo(smp) == false) return; + DeleteUndoStep(smp, UndoBuffer[smp - 1].size() - 1); } @@ -487,55 +485,55 @@ void CSampleUndo::RestrictBufferSize() //------------------------------------ { - UINT nCapacity = GetUndoBufferCapacity(); - while(nCapacity > CMainFrame::GetSettings().m_nSampleUndoMaxBuffer) + size_t capacity = GetUndoBufferCapacity(); + while(capacity > CMainFrame::GetSettings().m_nSampleUndoMaxBuffer) { for(SAMPLEINDEX smp = 1; smp <= UndoBuffer.size(); smp++) { if(UndoBuffer[smp - 1].size() != 0 && UndoBuffer[smp - 1][0].SamplePtr != nullptr) { - nCapacity -= (UndoBuffer[smp - 1][0].nChangeEnd - UndoBuffer[smp - 1][0].nChangeStart) * UndoBuffer[smp - 1][0].OldSample.GetBytesPerSample(); + capacity -= (UndoBuffer[smp - 1][0].nChangeEnd - UndoBuffer[smp - 1][0].nChangeStart) * UndoBuffer[smp - 1][0].OldSample.GetBytesPerSample(); DeleteUndoStep(smp, 0); } - if(nCapacity <= CMainFrame::GetSettings().m_nSampleUndoMaxBuffer) return; + if(capacity <= CMainFrame::GetSettings().m_nSampleUndoMaxBuffer) return; } } } // Return total amount of bytes used by the sample undo buffer. -UINT CSampleUndo::GetUndoBufferCapacity() -//--------------------------------------- +size_t CSampleUndo::GetUndoBufferCapacity() +//----------------------------------------- { - UINT nSum = 0; - for(size_t nSmp = 0; nSmp < UndoBuffer.size(); nSmp++) + size_t sum = 0; + for(size_t smp = 0; smp < UndoBuffer.size(); smp++) { - for(size_t nStep = 0; nStep < UndoBuffer[nSmp].size(); nStep++) + for(size_t nStep = 0; nStep < UndoBuffer[smp].size(); nStep++) { - if(UndoBuffer[nSmp][nStep].SamplePtr != nullptr) + if(UndoBuffer[smp][nStep].SamplePtr != nullptr) { - nSum += (UndoBuffer[nSmp][nStep].nChangeEnd - UndoBuffer[nSmp][nStep].nChangeStart) - * UndoBuffer[nSmp][nStep].OldSample.GetBytesPerSample(); + sum += (UndoBuffer[smp][nStep].nChangeEnd - UndoBuffer[smp][nStep].nChangeStart) + * UndoBuffer[smp][nStep].OldSample.GetBytesPerSample(); } } } - return nSum; + return sum; } // Ensure that the undo buffer is big enough for a given sample number -bool CSampleUndo::SampleBufferExists(const SAMPLEINDEX nSmp, bool bForceCreation) -//------------------------------------------------------------------------------- +bool CSampleUndo::SampleBufferExists(const SAMPLEINDEX smp, bool forceCreation) +//----------------------------------------------------------------------------- { - if(nSmp == 0 || nSmp > MAX_SAMPLES) return false; + if(smp == 0 || smp > MAX_SAMPLES) return false; // Sample slot exists already - if(nSmp <= UndoBuffer.size()) return true; + if(smp <= UndoBuffer.size()) return true; // Sample slot doesn't exist, don't create it. - if(bForceCreation == false) return false; + if(forceCreation == false) return false; // Sample slot doesn't exist, so create it. - UndoBuffer.resize(nSmp); + UndoBuffer.resize(smp); return true; -} \ No newline at end of file +} Modified: trunk/OpenMPT/mptrack/Undo.h =================================================================== --- trunk/OpenMPT/mptrack/Undo.h 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/mptrack/Undo.h 2012-06-07 13:55:37 UTC (rev 1292) @@ -16,36 +16,46 @@ ///////////////////////////////////////////////////////////////////////////////////////// // Pattern Undo -// Additional undo information, as required -struct PATTERNUNDOINFO -{ - ModChannelSettings *settings; - CHANNELINDEX oldNumChannels; -}; -struct PATTERNUNDOBUFFER -{ - PATTERNINDEX pattern; - ROWINDEX patternsize; - CHANNELINDEX firstChannel, numChannels; - ROWINDEX firstRow, numRows; - ModCommand *pbuffer; - PATTERNUNDOINFO *channelInfo; - bool linkToPrevious; -}; - //================ class CPatternUndo //================ { - protected: - std::vector<PATTERNUNDOBUFFER> UndoBuffer; + // Additional undo information, as required + struct ChannelInfo + { + ModChannelSettings *settings; + CHANNELINDEX oldNumChannels; + + ChannelInfo(CHANNELINDEX numChannels) : oldNumChannels(numChannels) + { + settings = new ModChannelSettings[numChannels]; + } + + ~ChannelInfo() + { + delete[] settings; + } + }; + + struct UndoInfo + { + PATTERNINDEX pattern; + ROWINDEX patternsize; + CHANNELINDEX firstChannel, numChannels; + ROWINDEX firstRow, numRows; + ModCommand *pbuffer; + ChannelInfo *channelInfo; + bool linkToPrevious; + }; + + std::vector<UndoInfo> UndoBuffer; CModDoc *m_pModDoc; // Pattern undo helper functions - void DeleteUndoStep(const UINT nStep); + void DeleteUndoStep(size_t step); PATTERNINDEX Undo(bool linkedFromPrevious); public: @@ -57,13 +67,14 @@ bool CanUndo(); void RemoveLastUndoStep(); - void SetParent(CModDoc *pModDoc) {m_pModDoc = pModDoc;} + void SetParent(CModDoc *pModDoc) { m_pModDoc = pModDoc; } CPatternUndo() { UndoBuffer.clear(); m_pModDoc = nullptr; }; + ~CPatternUndo() { ClearUndo(); @@ -89,49 +100,50 @@ sundo_replace, // replace complete sample (16->8Bit, up/downsample, downmix to mono, pitch shifting / time stretching, trimming, pasting) }; -struct SAMPLEUNDOBUFFER -{ - ModSample OldSample; - CHAR szOldName[MAX_SAMPLENAME]; - LPSTR SamplePtr; - UINT nChangeStart, nChangeEnd; - sampleUndoTypes nChangeType; -}; //=============== class CSampleUndo //=============== { - protected: + struct UndoInfo + { + ModSample OldSample; + char szOldName[MAX_SAMPLENAME]; + LPSTR SamplePtr; + SmpLength nChangeStart, nChangeEnd; + sampleUndoTypes nChangeType; + }; + // Undo buffer - std::vector<std::vector<SAMPLEUNDOBUFFER> > UndoBuffer; + std::vector<std::vector<UndoInfo> > UndoBuffer; CModDoc *m_pModDoc; // Sample undo helper functions - void DeleteUndoStep(const SAMPLEINDEX nSmp, const UINT nStep); - bool SampleBufferExists(const SAMPLEINDEX nSmp, bool bForceCreation = true); + void DeleteUndoStep(const SAMPLEINDEX smp, const size_t step); + bool SampleBufferExists(const SAMPLEINDEX smp, bool forceCreation = true); void RestrictBufferSize(); - UINT GetUndoBufferCapacity(); + size_t GetUndoBufferCapacity(); public: // Sample undo functions void ClearUndo(); - void ClearUndo(const SAMPLEINDEX nSmp); - bool PrepareUndo(const SAMPLEINDEX nSmp, sampleUndoTypes nChangeType, UINT nChangeStart = 0, UINT nChangeEnd = 0); - bool Undo(const SAMPLEINDEX nSmp); - bool CanUndo(const SAMPLEINDEX nSmp); - void RemoveLastUndoStep(const SAMPLEINDEX nSmp); + void ClearUndo(const SAMPLEINDEX smp); + bool PrepareUndo(const SAMPLEINDEX smp, sampleUndoTypes changeType, SmpLength changeStart = 0, SmpLength changeEnd = 0); + bool Undo(const SAMPLEINDEX smp); + bool CanUndo(const SAMPLEINDEX smp); + void RemoveLastUndoStep(const SAMPLEINDEX smp); - void SetParent(CModDoc *pModDoc) {m_pModDoc = pModDoc;} + void SetParent(CModDoc *pModDoc) { m_pModDoc = pModDoc; } CSampleUndo() { UndoBuffer.clear(); m_pModDoc = nullptr; }; + ~CSampleUndo() { ClearUndo(); Modified: trunk/OpenMPT/soundlib/ModSequence.h =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.h 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/soundlib/ModSequence.h 2012-06-07 13:55:37 UTC (rev 1292) @@ -100,7 +100,7 @@ bool ReadAsByte(const BYTE* pFrom, const int howMany, const int memLength); bool ReadAsByte(FileReader &file, size_t howMany); template<typename T, size_t arraySize> - bool ReadFromArray(T (&orders)[arraySize], size_t howMany = arraySize); + bool ReadFromArray(const T (&orders)[arraySize], size_t howMany = arraySize); // Deprecated function used for MPTm files created with OpenMPT 1.17.02.46 - 1.17.02.48. DWORD Deserialize(const BYTE* const src, const DWORD memLength); @@ -135,8 +135,8 @@ template<typename T, size_t arraySize> -bool ModSequence::ReadFromArray(T (&orders)[arraySize], size_t howMany) -//--------------------------------------------------------------------- +bool ModSequence::ReadFromArray(const T (&orders)[arraySize], size_t howMany) +//--------------------------------------------------------------------------- { LimitMax(howMany, arraySize); Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -62,23 +62,7 @@ extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); #endif -#define MAX_PACK_TABLES 3 - -// Compression table -static char UnpackTable[MAX_PACK_TABLES][16] = -//-------------------------------------------- -{ - // CPU-generated dynamic table - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - // u-Law table - 0, 1, 2, 4, 8, 16, 32, 64, - -1, -2, -4, -8, -16, -32, -48, -64, - // Linear table - 0, 1, 2, 3, 5, 7, 12, 19, - -1, -2, -3, -5, -7, -12, -19, -31, -}; - // -> CODE#0027 // -> DESC="per-instrument volume ramping setup (refered as attack)" @@ -463,7 +447,7 @@ m_ModFlags = 0; m_bITBidiMode = false; - m_pModDoc = NULL; + m_pModDoc = nullptr; m_dwLastSavedWithVersion=0; m_dwCreatedWithVersion=0; m_bChannelMuteTogglePending.reset(); @@ -1323,10 +1307,10 @@ Chn[nChn].Reset(ModChannel::resetTotal, *this, nChn); - if(m_pModDoc) + if(GetpModDoc() != nullptr) { - m_pModDoc->Record1Channel(nChn, false); - m_pModDoc->Record2Channel(nChn, false); + GetpModDoc()->Record1Channel(nChn, false); + GetpModDoc()->Record2Channel(nChn, false); } m_bChannelMuteTogglePending[nChn] = false; Modified: trunk/OpenMPT/soundlib/pattern.cpp =================================================================== --- trunk/OpenMPT/soundlib/pattern.cpp 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/soundlib/pattern.cpp 2012-06-07 13:55:37 UTC (rev 1292) @@ -12,15 +12,15 @@ #include "pattern.h" #include "patternContainer.h" #include "../mptrack/mainfrm.h" -#include "../mptrack/moddoc.h" #include "../mptrack/serialization_utils.h" #include "../mptrack/version.h" #include "ITTools.h" -CSoundFile& CPattern::GetSoundFile() {return m_rPatternContainer.GetSoundFile();} -const CSoundFile& CPattern::GetSoundFile() const {return m_rPatternContainer.GetSoundFile();} +CSoundFile& CPattern::GetSoundFile() { return m_rPatternContainer.GetSoundFile(); } +const CSoundFile& CPattern::GetSoundFile() const { return m_rPatternContainer.GetSoundFile(); } + CHANNELINDEX CPattern::GetNumChannels() const //------------------------------------------- { @@ -28,101 +28,69 @@ } +// Check if there is any note data on a given row. +bool CPattern::IsEmptyRow(ROWINDEX row) const +//------------------------------------------- +{ + if(m_ModCommands == nullptr || IsValidRow(row)) + { + return true; + } + + PatternRow data = GetRow(row); + for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, data++) + { + if(!data->IsEmpty()) + { + return false; + } + } + return true; +} + + bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) //------------------------------------------------------------------------------------ { - if(rowsPerBeat < GetSoundFile().GetModSpecifications().patternRowsMin || rowsPerBeat > GetSoundFile().GetModSpecifications().patternRowsMax - || rowsPerMeasure < rowsPerBeat || rowsPerMeasure > GetSoundFile().GetModSpecifications().patternRowsMax - /*|| rowsPerBeat > m_Rows || rowsPerMeasure > m_Rows*/) + if(rowsPerBeat < GetSoundFile().GetModSpecifications().patternRowsMin + || rowsPerBeat > GetSoundFile().GetModSpecifications().patternRowsMax + || rowsPerMeasure < rowsPerBeat + || rowsPerMeasure > GetSoundFile().GetModSpecifications().patternRowsMax) + { return false; + } m_RowsPerBeat = rowsPerBeat; m_RowsPerMeasure = rowsPerMeasure; return true; } -bool CPattern::Resize(const ROWINDEX newRowCount, const bool showDataLossWarning) -//------------------------------------------------------------------------------- +// Add or remove rows from the pattern. +bool CPattern::Resize(const ROWINDEX newRowCount) +//----------------------------------------------- { - if(m_ModCommands == nullptr) + CSoundFile &sndFile = GetSoundFile(); + const CModSpecifications& specs = sndFile.GetModSpecifications(); + ModCommand *newPattern; + + if(m_ModCommands == nullptr + || newRowCount == m_Rows + || newRowCount > specs.patternRowsMax + || newRowCount < specs.patternRowsMin + || (newPattern = AllocatePattern(newRowCount, GetNumChannels())) == nullptr) { - //For mimicing old behavior of setting patternsize before even having the - //actual pattern allocated. - m_Rows = newRowCount; return false; } + // Copy over pattern data + memcpy(newPattern, m_ModCommands, GetNumChannels() * Util::Min(m_Rows, newRowCount) * sizeof(ModCommand)); - CSoundFile& sndFile = m_rPatternContainer.GetSoundFile(); - const CModSpecifications& specs = sndFile.GetModSpecifications(); - if(sndFile.m_pModDoc == nullptr) return true; - CModDoc& rModDoc = *sndFile.m_pModDoc; - if(newRowCount > specs.patternRowsMax || newRowCount < specs.patternRowsMin) - return true; - - if (newRowCount == m_Rows) return false; - rModDoc.BeginWaitCursor(); - CriticalSection cs; + FreePattern(m_ModCommands); + m_ModCommands = newPattern; + m_Rows = newRowCount; - if (newRowCount > m_Rows) - { - ModCommand *p = AllocatePattern(newRowCount, sndFile.GetNumChannels()); - if (p) - { - memcpy(p, m_ModCommands, sndFile.GetNumChannels() * m_Rows * sizeof(ModCommand)); - FreePattern(m_ModCommands); - m_ModCommands = p; - m_Rows = newRowCount; - } - } else - { - bool bOk = true; - -#ifdef MODPLUG_TRACKER - if(showDataLossWarning) - { - // Check if any non-empty pattern cells would be lost when truncating rows at the bottom. - const ModCommand *m = GetpModCommand(newRowCount, 0); - for(size_t numCommands = (m_Rows - newRowCount) * sndFile.GetNumChannels(); numCommands != 0; numCommands--, m++) - { - if(!m->IsEmpty()) - { - bOk = false; - break; - } - } - - if (!bOk) - { - cs.Leave(); - rModDoc.EndWaitCursor(); - bOk = (Reporting::Confirm("Data at the end of the pattern will be lost.\nDo you want to continue?", "Shrink Pattern") == cnfYes); - rModDoc.BeginWaitCursor(); - cs.Enter(); - } - } -#endif // MODPLUG_TRACKER - - if (bOk) - { - ModCommand *pnew = AllocatePattern(newRowCount, sndFile.GetNumChannels()); - if (pnew) - { - memcpy(pnew, m_ModCommands, sndFile.GetNumChannels() * newRowCount * sizeof(ModCommand)); - FreePattern(m_ModCommands); - m_ModCommands = pnew; - m_Rows = newRowCount; - } - } - } - - cs.Leave(); - - rModDoc.EndWaitCursor(); - rModDoc.SetModified(); - - return (newRowCount == m_Rows) ? false : true; + return true; } @@ -152,97 +120,90 @@ } + void CPattern::Deallocate() //------------------------- { - // Removed critical section as it can cause problems when destroying patterns in the CSoundFile destructor. - //BEGIN_CRITICAL(); m_Rows = m_RowsPerBeat = m_RowsPerMeasure = 0; FreePattern(m_ModCommands); m_ModCommands = nullptr; m_PatternName.Empty(); - //END_CRITICAL(); } + bool CPattern::Expand() //--------------------- { - ModCommand *newPattern, *oldPattern; + const ROWINDEX newRows = m_Rows * 2; + const CHANNELINDEX nChns = GetNumChannels(); + ModCommand *newPattern; - CSoundFile& sndFile = m_rPatternContainer.GetSoundFile(); - if(sndFile.m_pModDoc == nullptr) return true; + if(!m_ModCommands + || newRows > GetSoundFile().GetModSpecifications().patternRowsMax + || (newPattern = AllocatePattern(newRows, nChns)) == nullptr) + { + return false; + } - CModDoc& rModDoc = *sndFile.m_pModDoc; - - if ((!m_ModCommands) || (m_Rows > sndFile.GetModSpecifications().patternRowsMax / 2)) return true; - - rModDoc.BeginWaitCursor(); - const ROWINDEX nRows = m_Rows; - const CHANNELINDEX nChns = sndFile.m_nChannels; - newPattern = AllocatePattern(nRows * 2, nChns); - if (!newPattern) return true; - - const PATTERNINDEX nPattern = m_rPatternContainer.GetIndex(this); - rModDoc.GetPatternUndo().PrepareUndo(nPattern, 0, 0, nChns, nRows); - oldPattern = m_ModCommands; - for (ROWINDEX y = 0; y < nRows; y++) + for(ROWINDEX y = 0; y < m_Rows; y++) { - memcpy(newPattern + y * 2 * nChns, oldPattern + y * nChns, nChns * sizeof(ModCommand)); + memcpy(newPattern + y * 2 * nChns, m_ModCommands + y * nChns, nChns * sizeof(ModCommand)); } + + CriticalSection cs; + FreePattern(m_ModCommands); m_ModCommands = newPattern; - m_Rows = nRows * 2; - FreePattern(oldPattern); oldPattern = nullptr; - rModDoc.SetModified(); - rModDoc.UpdateAllViews(NULL, HINT_PATTERNDATA | (nPattern << HINT_SHIFT_PAT), NULL); - rModDoc.EndWaitCursor(); - return false; + m_Rows = newRows; + + return true; } + bool CPattern::Shrink() //--------------------- { - CSoundFile& sndFile = m_rPatternContainer.GetSoundFile(); - if(sndFile.m_pModDoc == NULL) return true; + if (!m_ModCommands + || m_Rows < GetSoundFile().GetModSpecifications().patternRowsMin * 2) + { + return false; + } - CModDoc& rModDoc = *sndFile.m_pModDoc; + m_Rows /= 2; + const CHANNELINDEX nChns = GetNumChannels(); - if (!m_ModCommands || m_Rows < sndFile.GetModSpecifications().patternRowsMin * 2) return true; - - rModDoc.BeginWaitCursor(); - ROWINDEX nRows = m_Rows; - const CHANNELINDEX nChns = sndFile.m_nChannels; - const PATTERNINDEX nPattern = m_rPatternContainer.GetIndex(this); - rModDoc.GetPatternUndo().PrepareUndo(nPattern, 0, 0, nChns, nRows); - nRows /= 2; - for (ROWINDEX y = 0; y < nRows; y++) + for(ROWINDEX y = 0; y < m_Rows; y++) { - ModCommand *psrc = sndFile.Patterns[nPattern] + (y * 2 * nChns); - ModCommand *pdest = sndFile.Patterns[nPattern] + (y * nChns); - for (CHANNELINDEX x = 0; x < nChns; x++) + const PatternRow srcRow = GetRow(y * 2); + const PatternRow nextSrcRow = GetRow(y * 2 + 1); + PatternRow destRow = GetRow(y); + + for(CHANNELINDEX x = 0; x < nChns; x++) { - pdest[x] = psrc[x]; - if ((!pdest[x].note) && (!pdest[x].instr)) + const ModCommand &src = srcRow[x]; + const ModCommand &srcNext = nextSrcRow[x]; + ModCommand &dest = destRow[x]; + dest = src; + + if(dest.note == NOTE_NONE && !dest.instr) { - pdest[x].note = psrc[x+nChns].note; - pdest[x].instr = psrc[x+nChns].instr; - if (psrc[x+nChns].volcmd) + // Fill in data from next row if field is empty + dest.note = srcNext.note; + dest.instr = srcNext.instr; + if(srcNext.volcmd != VOLCMD_NONE) { - pdest[x].volcmd = psrc[x+nChns].volcmd; - pdest[x].vol = psrc[x+nChns].vol; + dest.volcmd = srcNext.volcmd; + dest.vol = srcNext.vol; } - if (!pdest[x].command) + if(dest.command == CMD_NONE) { - pdest[x].command = psrc[x+nChns].command; - pdest[x].param = psrc[x+nChns].param; + dest.command = srcNext.command; + dest.param = srcNext.param; } } } } - m_Rows = nRows; - rModDoc.SetModified(); - rModDoc.UpdateAllViews(NULL, HINT_PATTERNDATA | (nPattern << HINT_SHIFT_PAT), NULL); - rModDoc.EndWaitCursor(); - return false; + + return true; } Modified: trunk/OpenMPT/soundlib/pattern.h =================================================================== --- trunk/OpenMPT/soundlib/pattern.h 2012-05-30 16:45:20 UTC (rev 1291) +++ trunk/OpenMPT/soundlib/pattern.h 2012-06-07 13:55:37 UTC (rev 1292) @@ -62,10 +62,14 @@ PatternRow GetRow(const ROWINDEX row) { return GetpModCommand(row, 0); } const PatternRow GetRow(const ROWINDEX row) const { return const_cast<ModCommand *>(GetpModCommand(row, 0)); } - CHANNELINDEX GetNumChannels() const; + inline CHANNELINDEX GetNumChannels() const; - bool Resize(const ROWINDEX newRowCount, const bool showDataLossWarning = true); + // Add or remove rows from the pattern. + bool Resize(const ROWINDEX newRowCount); + // Check if there is any note data on a given row. + bool IsEmptyRow(ROWINDEX row) const; + // Allocate new pattern memory and replace old pattern data. bool AllocatePattern(ROWINDEX rows); // Deallocate pattern data. @@ -126,8 +130,8 @@ ModCommand& GetModCommand(size_t i) { return m_ModCommands[i]; } //Returns modcommand from (floor[i/channelCount], i%channelCount) - ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) { return m_ModCommands[r*GetNumChannels()+c]; } - const ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) const { return m_ModCommands[r*GetNumChannels()+c]; } + ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) { return m_ModCommands[r * GetNumChannels() + c]; } + const ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) const { return m_ModCommands[r * GetNumChannels() + c]; } //BEGIN: DATA This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-07 13:58:26
|
Revision: 1293 http://modplug.svn.sourceforge.net/modplug/?rev=1293&view=rev Author: saga-games Date: 2012-06-07 13:58:15 +0000 (Thu, 07 Jun 2012) Log Message: ----------- [Fix] Oops. Modified Paths: -------------- trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp trunk/OpenMPT/soundlib/pattern.cpp Modified: trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2012-06-07 13:55:37 UTC (rev 1292) +++ trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2012-06-07 13:58:15 UTC (rev 1293) @@ -581,15 +581,12 @@ // Check if any pattern data would be removed. bool resize = true; - if(newSize < pSndFile->Patterns[m_nPattern].GetNumRows()) + for(ROWINDEX row = newSize; row < pSndFile->Patterns[m_nPattern].GetNumRows(); row++) { - for(ROWINDEX row = newSize; row < pSndFile->Patterns[m_nPattern].GetNumRows(); row++) + if(!pSndFile->Patterns[m_nPattern].IsEmptyRow(row)) { - if(!pSndFile->Patterns[m_nPattern].IsEmptyRow(row)) - { - resize = (Reporting::Confirm("Data at the end of the pattern will be lost.\nDo you want to continue?", "Shrink Pattern") == cnfYes); - break; - } + resize = (Reporting::Confirm("Data at the end of the pattern will be lost.\nDo you want to continue?", "Shrink Pattern") == cnfYes); + break; } } Modified: trunk/OpenMPT/soundlib/pattern.cpp =================================================================== --- trunk/OpenMPT/soundlib/pattern.cpp 2012-06-07 13:55:37 UTC (rev 1292) +++ trunk/OpenMPT/soundlib/pattern.cpp 2012-06-07 13:58:15 UTC (rev 1293) @@ -32,7 +32,7 @@ bool CPattern::IsEmptyRow(ROWINDEX row) const //------------------------------------------- { - if(m_ModCommands == nullptr || IsValidRow(row)) + if(m_ModCommands == nullptr || !IsValidRow(row)) { return true; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-12 15:45:23
|
Revision: 1298 http://modplug.svn.sourceforge.net/modplug/?rev=1298&view=rev Author: saga-games Date: 2012-06-12 15:45:16 +0000 (Tue, 12 Jun 2012) Log Message: ----------- [Fix] Insufficient sample loop validity checks when sanitizing samples. [Mod] OpenMPT: Version is now 1.20.01.07 Modified Paths: -------------- trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Sndfile.cpp Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-06-09 11:45:45 UTC (rev 1297) +++ trunk/OpenMPT/mptrack/version.h 2012-06-12 15:45:16 UTC (rev 1298) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 06 +#define VER_MINORMINOR 07 //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/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-09 11:45:45 UTC (rev 1297) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-12 15:45:16 UTC (rev 1298) @@ -1329,7 +1329,9 @@ // Fix bad loops // Second condition is to fix some old S3M files which have very short loops just before some garbage data. Very dirty method (just like the rest of this "fixing")! - if((sample.nLoopEnd + 3 >= numSamples || sample.nLoopEnd == sample.nLoopStart + 1) && (sample.uFlags & (CHN_LOOP | CHN_PINGPONGLOOP | CHN_STEREO)) == CHN_LOOP) + if((sample.nLoopEnd + 3 >= numSamples || sample.nLoopEnd == sample.nLoopStart + 1) + && sample.nLoopEnd <= sample.nLength && sample.nLoopStart < sample.nLoopEnd + && (sample.uFlags & (CHN_LOOP | CHN_PINGPONGLOOP | CHN_STEREO)) == CHN_LOOP) { data[sample.nLoopEnd] = data[sample.nLoopStart]; data[sample.nLoopEnd + 1] = data[sample.nLoopStart + 1]; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-15 21:48:56
|
Revision: 1300 http://modplug.svn.sourceforge.net/modplug/?rev=1300&view=rev Author: saga-games Date: 2012-06-15 21:48:47 +0000 (Fri, 15 Jun 2012) Log Message: ----------- [Fix] MO3: Import was broken since revision 1278. [Ref] Rewrote the "TryWriteEffect" mechanism a bit. Is now part of CPattern instead of CSoundFile. Revision Links: -------------- http://modplug.svn.sourceforge.net/modplug/?rev=1278&view=rev Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_pat.cpp trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/MPTHacks.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/soundlib/LOAD_DMF.CPP trunk/OpenMPT/soundlib/Load_669.cpp trunk/OpenMPT/soundlib/Load_far.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Load_med.cpp trunk/OpenMPT/soundlib/Load_mo3.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_psm.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Load_stm.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/modcommand.cpp trunk/OpenMPT/soundlib/modcommand.h trunk/OpenMPT/soundlib/pattern.cpp trunk/OpenMPT/soundlib/pattern.h Modified: trunk/OpenMPT/mptrack/Ctrl_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -343,7 +343,7 @@ nPat = (PATTERNINDEX)(dwHintMask >> HINT_SHIFT_PAT); else nPat = (PATTERNINDEX)SendViewMessage(VIEWMSG_GETCURRENTPATTERN); - m_pSndFile->Patterns[nPat].GetName(s, CountOf(s)); + m_pSndFile->Patterns[nPat].GetName(s); m_EditPatName.SetWindowText(s); BOOL bXMIT = (m_pSndFile->GetType() & (MOD_TYPE_XM|MOD_TYPE_IT|MOD_TYPE_MPT)) ? TRUE : FALSE; Modified: trunk/OpenMPT/mptrack/Ctrl_seq.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -746,10 +746,10 @@ PATTERNINDEX nPat = pSndFile->Order[m_nScrollPos]; if (nPat < pSndFile->Patterns.Size()) { - CHAR szpat[MAX_PATTERNNAME] = ""; - if (pSndFile->Patterns[nPat].GetName(szpat, MAX_PATTERNNAME) && strlen(szpat)) + char szpat[MAX_PATTERNNAME] = ""; + if (pSndFile->Patterns[nPat].GetName(szpat) && strcmp(szpat, "")) { - wsprintf(s+strlen(s), ": %s", szpat); + wsprintf(s + strlen(s), ": %s", szpat); } } } Modified: trunk/OpenMPT/mptrack/MPTHacks.cpp =================================================================== --- trunk/OpenMPT/mptrack/MPTHacks.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/mptrack/MPTHacks.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -263,7 +263,7 @@ if(autofix) { m_SndFile.Patterns[i].Resize(originalSpecs->patternRowsMin); - m_SndFile.TryWriteEffect(i, patSize - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weTryNextRow); + m_SndFile.Patterns[i].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(patSize - 1).Retry(EffectWriter::rmTryNextRow)); } else { break; Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -136,12 +136,15 @@ // Resizing all patterns to 64 rows for(PATTERNINDEX nPat = 0; nPat < m_SndFile.Patterns.Size(); nPat++) if ((m_SndFile.Patterns[nPat]) && (m_SndFile.Patterns[nPat].GetNumRows() != 64)) { - // try to save short patterns by inserting a pattern break. - if(m_SndFile.Patterns[nPat].GetNumRows() < 64) + ROWINDEX origRows = m_SndFile.Patterns[nPat].GetNumRows(); + m_SndFile.Patterns[nPat].Resize(64); + + if(origRows < 64) { - m_SndFile.TryWriteEffect(nPat, m_SndFile.Patterns[nPat].GetNumRows() - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weTryNextRow); + // Try to save short patterns by inserting a pattern break. + m_SndFile.Patterns[nPat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(m_SndFile.Patterns[nPat].GetNumRows() - 1).Retry(EffectWriter::rmTryNextRow)); } - m_SndFile.Patterns[nPat].Resize(64); + CHANGEMODTYPE_WARNING(wResizedPatterns); } @@ -283,7 +286,7 @@ } if(addBreak) { - m_SndFile.TryWriteEffect(nPat, m_SndFile.Patterns[nPat].GetNumRows() - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weIgnore); + m_SndFile.Patterns[nPat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(m_SndFile.Patterns[nPat].GetNumRows() - 1)); } } Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -924,7 +924,7 @@ GetLengthType length = m_SndFile.GetLength(eNoAdjust); if(length.endOrder != ORDERINDEX_INVALID && length.endRow != ROWINDEX_INVALID) { - result = m_SndFile.TryWriteEffect(m_SndFile.Order[length.endOrder], length.endRow, CMD_POSITIONJUMP, m_SndFile.m_nRestartPos, false, CHANNELINDEX_INVALID, false, weTryNextRow); + result = m_SndFile.Patterns[m_SndFile.Order[length.endOrder]].WriteEffect(EffectWriter(CMD_POSITIONJUMP, m_SndFile.m_nRestartPos).Row(length.endRow).Retry(EffectWriter::rmTryNextRow)); } m_SndFile.m_nRestartPos = 0; return result; @@ -940,7 +940,7 @@ { for(ORDERINDEX i = 0; i < m_SndFile.Order.GetLength(); i++) { - if(m_SndFile.TryWriteEffect(m_SndFile.Order[i], 0, CMD_GLOBALVOLUME, m_SndFile.m_nDefaultGlobalVolume * 64 / MAX_GLOBAL_VOLUME, false, CHANNELINDEX_INVALID, false, weTryNextRow)) + if(m_SndFile.Patterns[m_SndFile.Order[i]].WriteEffect(EffectWriter(CMD_GLOBALVOLUME, m_SndFile.m_nDefaultGlobalVolume * 64 / MAX_GLOBAL_VOLUME).Retry(EffectWriter::rmTryNextRow))) { result = true; break; Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-06-15 21:48:47 UTC (rev 1300) @@ -488,7 +488,7 @@ // Put high offset on previous row if(nRow > 0) { - pSndFile->TryWriteEffect(nPat, nRow - 1, CMD_S3MCMDEX, (0xA0 | (effect1 - 6)), false, nChn, false, weTryPreviousRow); + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(nRow - 1).Channel(nChn).Retry(EffectWriter::rmTryPreviousRow)); } effect1 = CMD_OFFSET; settings.playDir[nChn] = false; @@ -518,7 +518,7 @@ switch(effect2) { case 1: // Note Finetune - effect2 = (effectParam2 < 128) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; + effect2 = static_cast<ModCommand::COMMAND>(effectParam2 < 128 ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN); if(effectParam2 > 128) effectParam2 = 255 - effectParam2 + 1; effectParam2 = 0xF0 | min(0x0F, effectParam2); // Well, this is not too accurate... break; @@ -539,7 +539,7 @@ case 4: // Portamento Up case 5: // Portamento Down effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, true); - effect2 = (effect2 == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; + effect2 = static_cast<ModCommand::COMMAND>(effect2 == 4 ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN); break; case 6: // Portamento to Note if(m->note == NOTE_NONE) @@ -560,7 +560,7 @@ // Put vibrato type on previous row if(nRow > 0) { - pSndFile->TryWriteEffect(nPat, nRow - 1, CMD_S3MCMDEX, (0x30 | (effect2 - 8)), false, nChn, false, weTryPreviousRow); + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(nRow - 1).Channel(nChn).Retry(EffectWriter::rmTryPreviousRow)); } effect2 = CMD_VIBRATO; effectParam2 = DMFvibrato2MPT(effectParam2, settings.internalTicks); @@ -612,7 +612,7 @@ // Put tremolo type on previous row if(nRow > 0) { - pSndFile->TryWriteEffect(nPat, nRow - 1, CMD_S3MCMDEX, (0x40 | (effect3 - 4)), false, nChn, false, weTryPreviousRow); + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(nRow - 1).Channel(nChn).Retry(EffectWriter::rmTryPreviousRow)); } effect3 = CMD_TREMOLO; effectParam3 = DMFvibrato2MPT(effectParam3, settings.internalTicks); @@ -717,18 +717,19 @@ if(tempoChange) { tempoChange = false; - pSndFile->TryWriteEffect(nPat, nRow, CMD_TEMPO, (BYTE)tempo, false, 0, false, weTryNextRow); - pSndFile->TryWriteEffect(nPat, nRow, CMD_SPEED, (BYTE)speed, false, CHANNELINDEX_INVALID, false, weTryNextRow); + + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast<ModCommand::PARAM>(tempo)).Row(nRow).Channel(0).Retry(EffectWriter::rmTryNextRow)); + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_SPEED, static_cast<ModCommand::PARAM>(speed)).Row(nRow).Retry(EffectWriter::rmTryNextRow)); } // Try to put delay effects somewhere as well if(writeDelay & 0xF0) { - pSndFile->TryWriteEffect(nPat, nRow, CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4), false, CHANNELINDEX_INVALID, true, weIgnore); + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(nRow).AllowMultiple().Retry(EffectWriter::rmIgnore)); } if(writeDelay & 0x0F) { const uint8 param = (writeDelay & 0x0F) * settings.internalTicks / 15; - pSndFile->TryWriteEffect(nPat, nRow, CMD_S3MCMDEX, 0x60 | CLAMP(param, 1, 15), false, CHANNELINDEX_INVALID, true, weIgnore); + pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(nRow).AllowMultiple().Retry(EffectWriter::rmIgnore)); } writeDelay = 0; } // End for all rows @@ -1003,7 +1004,7 @@ // Loop end? if(nPat != PATTERNINDEX_INVALID && nOrd == loopEnd && (loopStart > 0 || nOrd < Order.GetLength() - 1)) { - TryWriteEffect(nPat, Patterns[nPat].GetNumRows() - 1, CMD_POSITIONJUMP, (BYTE)loopStart, false, CHANNELINDEX_INVALID, false, weTryPreviousRow); + Patterns[nPat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(loopStart)).Row(Patterns[nPat].GetNumRows() - 1).Retry(EffectWriter::rmTryPreviousRow)); } } } Modified: trunk/OpenMPT/soundlib/Load_669.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_669.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_669.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -208,7 +208,7 @@ // Write pattern break if(fileHeader.breaks[pat] < 63) { - TryWriteEffect(pat, fileHeader.breaks[pat], CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weTryPreviousRow); + Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(fileHeader.breaks[pat]).Retry(EffectWriter::rmTryNextRow)); } } } Modified: trunk/OpenMPT/soundlib/Load_far.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_far.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_far.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -278,7 +278,7 @@ } } - TryWriteEffect(pat, breakRow, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weTryNextRow); + Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(breakRow).Retry(EffectWriter::rmTryNextRow)); } // Read samples @@ -300,16 +300,9 @@ m_nSamples = smp + 1; ModSample &sample = Samples[m_nSamples]; - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[m_nSamples], sampleHeader.name); - - sampleHeader.ConvertToMPT(sample); - - if(sample.nLength) - { - sampleHeader.GetSampleFormat().ReadSample(sample, file); - } + sampleHeader.GetSampleFormat().ReadSample(sample, file); } return true; } Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -1262,7 +1262,7 @@ { char name[MAX_PATTERNNAME]; MemsetZero(name); - Patterns[nPat].GetName(name, MAX_PATTERNNAME); + Patterns[nPat].GetName(name); fwrite(name, 1, MAX_PATTERNNAME, f); } } Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -564,7 +564,7 @@ { char name[MAX_PATTERNNAME]; MemsetZero(name); - Patterns[nPat].GetName(name, MAX_PATTERNNAME); + Patterns[nPat].GetName(name); fwrite(name, 1, MAX_PATTERNNAME, f); } Modified: trunk/OpenMPT/soundlib/Load_med.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_med.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_med.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -300,7 +300,7 @@ } else command = 0; } break; - case 0x09: command = (param <= 0x20) ? CMD_SPEED : CMD_TEMPO; break; + case 0x09: command = static_cast<ModCommand::COMMAND>((param <= 0x20) ? CMD_SPEED : CMD_TEMPO); break; case 0x0D: if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break; case 0x0F: // Set Tempo / Special // F.00 = Pattern Break Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -15,21 +15,14 @@ #include "../mptrack/Mptrack.h" #endif // MODPLUG_TRACKER -#ifndef NO_MO3_SUPPORT -// Decode a MO3 file (returns the same "exit codes" as UNMO3.EXE, eg. 0=success) -// IN: data/len = MO3 data/len -// OUT: data/len = decoded data/len (if successful) -typedef int (WINAPI * UNMO3_DECODE)(const void **data, int *len); -// Free the data returned by UNMO3_Decode -typedef void (WINAPI * UNMO3_FREE)(const void *data); - -#endif // NO_MO3_SUPPORT - bool CSoundFile::ReadMO3(FileReader &file) //---------------------------------------- { file.Rewind(); + const void *stream = file.GetRawData(); + int length = file.GetLength(); + // No valid MO3 file (magic bytes: "MO3") if(file.GetLength() < 8 || !file.ReadMagic("MO3")) { @@ -46,7 +39,7 @@ } #ifdef MODPLUG_TRACKER - if(m_pModDoc != nullptr) m_pModDoc->AddToLog(GetStrI18N(_TEXT("The file appears to be a MO3 file, but this OpenMPT build does not support loading MO3 files."))); + if(GetpModDoc() != nullptr) GetpModDoc()->AddToLog(GetStrI18N(_TEXT("The file appears to be a MO3 file, but this OpenMPT build does not support loading MO3 files."))); #endif // MODPLUG_TRACKER return false; @@ -66,23 +59,26 @@ if(unmo3 == nullptr) // Didn't succeed. { #ifdef MODPLUG_TRACKER - if(m_pModDoc != nullptr) m_pModDoc->AddToLog(GetStrI18N(_TEXT("Loading MO3 file failed because unmo3.dll could not be loaded."))); + if(GetpModDoc() != nullptr) GetpModDoc()->AddToLog(GetStrI18N(_TEXT("Loading MO3 file failed because unmo3.dll could not be loaded."))); #endif // MODPLUG_TRACKER } else // case: dll loaded succesfully. { + // Decode a MO3 file (returns the same "exit codes" as UNMO3.EXE, eg. 0=success) + // IN: data/len = MO3 data/len + // OUT: data/len = decoded data/len (if successful) + typedef int (WINAPI * UNMO3_DECODE)(const void **data, int *len); + // Free the data returned by UNMO3_Decode + typedef void (WINAPI * UNMO3_FREE)(const void *data); + UNMO3_DECODE UNMO3_Decode = (UNMO3_DECODE)GetProcAddress(unmo3, "UNMO3_Decode"); UNMO3_FREE UNMO3_Free = (UNMO3_FREE)GetProcAddress(unmo3, "UNMO3_Free"); if(UNMO3_Decode != nullptr && UNMO3_Free != nullptr) { - const void *stream = file.GetRawData(); - int length = file.GetLength(); - if(UNMO3_Decode(&stream, &length) == 0) { // If decoding was successful, stream and length will keep the new pointers now. - if(length > 0) { FileReader unpackedFile(static_cast<const char *>(stream), length); @@ -101,4 +97,4 @@ } return result; #endif // NO_MO3_SUPPORT -} \ No newline at end of file +} Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -32,7 +32,7 @@ case 0x0C: m.command = CMD_VOLUME; break; case 0x0D: m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; case 0x0E: m.command = CMD_MODCMDEX; break; - case 0x0F: m.command = (m.param <= ((GetType() & (MOD_TYPE_MOD)) ? 0x20u : 0x1Fu)) ? CMD_SPEED : CMD_TEMPO; + case 0x0F: m.command = static_cast<ModCommand::COMMAND>((m.param <= ((GetType() & (MOD_TYPE_MOD)) ? 0x20u : 0x1Fu)) ? CMD_SPEED : CMD_TEMPO); if ((m.param == 0xFF) && (GetNumSamples() == 15) && (GetType() & MOD_TYPE_MOD)) m.command = CMD_NONE; break; //<rewbs> what the hell is this?! :) //<jojo> it's the "stop tune" command! :-P // Extension for XM extended effects Modified: trunk/OpenMPT/soundlib/Load_psm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_psm.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_psm.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -903,15 +903,18 @@ { for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - 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[chn], false, chn, false, weTryNextRow); + if(subsongs[i].channelSurround[chn]) + { + Patterns[startPattern].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x91).Row(0).Channel(chn).Retry(EffectWriter::rmTryNextRow)); + } else + { + Patterns[startPattern].WriteEffect(EffectWriter(CMD_PANNING8, subsongs[i].channelPanning[chn]).Row(0).Channel(chn).Retry(EffectWriter::rmTryNextRow)); + } } } // write default tempo/speed to pattern - TryWriteEffect(startPattern, 0, CMD_SPEED, subsongs[i].defaultSpeed, false, CHANNELINDEX_INVALID, false, weTryNextRow); - TryWriteEffect(startPattern, 0, CMD_TEMPO, subsongs[i].defaultTempo, false, CHANNELINDEX_INVALID, false, weTryNextRow); + Patterns[startPattern].WriteEffect(EffectWriter(CMD_SPEED, subsongs[i].defaultSpeed).Row(0).Retry(EffectWriter::rmTryNextRow)); + Patterns[startPattern].WriteEffect(EffectWriter(CMD_TEMPO, subsongs[i].defaultTempo).Row(0).Retry(EffectWriter::rmTryNextRow)); // don't write channel volume for now, as it's always set to 100% anyway @@ -929,7 +932,7 @@ break; } } - TryWriteEffect(endPattern, lastRow, CMD_POSITIONJUMP, (BYTE)subsongs[i].restartPos, false, CHANNELINDEX_INVALID, false, weTryNextRow); + Patterns[endPattern].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(subsongs[i].restartPos)).Row(lastRow).Retry(EffectWriter::rmTryPreviousRow)); } } } @@ -1396,7 +1399,7 @@ // Pattern break for short patterns (so saving the modules as S3M won't break it) if(patternHeader.numRows != 64) { - TryWriteEffect(pat, patternHeader.numRows - 1, CMD_PATTERNBREAK, 0, false, CHANNELINDEX_INVALID, false, weTryNextRow); + Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(patternHeader.numRows - 1).Retry(EffectWriter::rmTryNextRow)); } } } Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -47,7 +47,7 @@ case 'X': m.command = CMD_PANNING8; break; case 'Y': m.command = CMD_PANBRELLO; break; case 'Z': m.command = CMD_MIDI; break; - case '\\': m.command = fromIT ? CMD_SMOOTHMIDI : CMD_MIDI; break; //rewbs.smoothVST + case '\\': m.command = static_cast<ModCommand::COMMAND>(fromIT ? CMD_SMOOTHMIDI : CMD_MIDI); break; //rewbs.smoothVST // Chars under 0x40 don't save properly, so map : to ] and # to [. case ']': m.command = CMD_DELAYCUT; break; case '[': m.command = CMD_XPARAM; break; Modified: trunk/OpenMPT/soundlib/Load_stm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_stm.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_stm.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -261,7 +261,7 @@ if(breakPos != ORDERINDEX_INVALID) { - TryWriteEffect(pat, breakRow, CMD_POSITIONJUMP, breakPos, false, CHANNELINDEX_INVALID, false, weTryPreviousRow); + Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, breakPos).Row(breakRow).Retry(EffectWriter::rmTryPreviousRow)); } } Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -937,7 +937,7 @@ { char name[MAX_PATTERNNAME]; MemsetZero(name); - Patterns[nPat].GetName(name, MAX_PATTERNNAME); + Patterns[nPat].GetName(name); fwrite(name, 1, MAX_PATTERNNAME, f); } } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-06-15 21:48:47 UTC (rev 1300) @@ -120,15 +120,6 @@ }; -// Row advance mode for TryWriteEffect() -enum writeEffectAllowRowChange -{ - weIgnore, // If effect can't be written, abort. - weTryNextRow, // If effect can't be written, try next row. - weTryPreviousRow, // If effect can't be written, try previous row. -}; - - // Delete samples assigned to instrument enum deleteInstrumentSamples { @@ -594,9 +585,6 @@ } public: - // Write pattern effect functions - bool TryWriteEffect(PATTERNINDEX nPat, ROWINDEX nRow, BYTE nEffect, BYTE nParam, bool bIsVolumeEffect, CHANNELINDEX nChn = CHANNELINDEX_INVALID, bool bAllowMultipleEffects = true, writeEffectAllowRowChange allowRowChange = weIgnore, bool bRetry = true); - bool DestroySample(SAMPLEINDEX nSample); // -> CODE#0020 Modified: trunk/OpenMPT/soundlib/modcommand.cpp =================================================================== --- trunk/OpenMPT/soundlib/modcommand.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/modcommand.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -101,7 +101,7 @@ if(param == 0xA4) { // surround remap - command = (toType & (MOD_TYPE_IT|MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN; + command = static_cast<ModCommand::COMMAND>((toType & (MOD_TYPE_IT | MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN); param = 0x91; } else @@ -123,7 +123,7 @@ { if(IsPcNote()) { - ModCommand::COMMAND newcommand = (note == NOTE_PC) ? CMD_MIDI : CMD_SMOOTHMIDI; + ModCommand::COMMAND newcommand = static_cast<ModCommand::COMMAND>(note == NOTE_PC ? CMD_MIDI : CMD_SMOOTHMIDI); if(!CSoundFile::GetModSpecifications(toType).HasCommand(newcommand)) { newcommand = CMD_MIDI; // assuming that this was CMD_SMOOTHMIDI @@ -800,171 +800,7 @@ } -/* Try to write an (volume column) effect in a given channel or any channel of a pattern in a specific row. - Usage: - nPat - Pattern that should be modified - nRow - Row that should be modified - nEffect - (Volume) Effect that should be written - nParam - Effect that should be written - bIsVolumeEffect - Indicates whether the given effect is a volume column effect or not - nChn - Channel that should be modified - use CHANNELINDEX_INVALID to allow all channels of the given row - bAllowMultipleEffects - If false, No effect will be written if an effect of the same type is already present in the channel(s). Useful for e.g. tempo effects. - allowRowChange - Indicates whether it is allowed to use the next or previous row if there's no space for the effect - bRetry - For internal use only. Indicates whether an effect "rewrite" has already taken place (for recursive calls) - NOTE: Effect remapping is only implemented for a few basic effects. -*/ -bool CSoundFile::TryWriteEffect(PATTERNINDEX nPat, ROWINDEX nRow, BYTE nEffect, BYTE nParam, bool bIsVolumeEffect, CHANNELINDEX nChn, bool bAllowMultipleEffects, writeEffectAllowRowChange allowRowChange, bool bRetry) -//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -{ - // First, reject invalid parameters. - if(!Patterns.IsValidPat(nPat) || nRow >= Patterns[nPat].GetNumRows() || (nChn >= GetNumChannels() && nChn != CHANNELINDEX_INVALID)) - { - return false; - } - - CHANNELINDEX nScanChnMin = nChn, nScanChnMax = nChn; - - // Scan all channels - if(nChn == CHANNELINDEX_INVALID) - { - nScanChnMin = 0; - nScanChnMax = GetNumChannels() - 1; - } - - ModCommand * const p = Patterns[nPat].GetpModCommand(nRow, nScanChnMin); - ModCommand *m; - - // Scan channel(s) for same effect type - if an effect of the same type is already present, exit. - if(!bAllowMultipleEffects) - { - m = p; - for(CHANNELINDEX i = nScanChnMin; i <= nScanChnMax; i++, m++) - { - if(!bIsVolumeEffect && m->command == nEffect) - return true; - if(bIsVolumeEffect && m->volcmd == nEffect) - return true; - } - } - - // Easy case: check if there's some space left to put the effect somewhere - m = p; - for(CHANNELINDEX i = nScanChnMin; i <= nScanChnMax; i++, m++) - { - if(!bIsVolumeEffect && m->command == CMD_NONE) - { - m->command = nEffect; - m->param = nParam; - return true; - } - if(bIsVolumeEffect && m->volcmd == VOLCMD_NONE) - { - m->volcmd = nEffect; - m->vol = nParam; - return true; - } - } - - // Ok, apparently there's no space. If we haven't tried already, try to map it to the volume column or effect column instead. - if(bRetry) - { - // Move some effects that also work in the volume column, so there's place for our new effect. - if(!bIsVolumeEffect) - { - m = p; - for(CHANNELINDEX i = nScanChnMin; i <= nScanChnMax; i++, m++) - { - switch(m->command) - { - case CMD_VOLUME: - m->volcmd = VOLCMD_VOLUME; - m->vol = m->param; - m->command = nEffect; - m->param = nParam; - return true; - - case CMD_PANNING8: - if(m_nType & MOD_TYPE_S3M && nParam > 0x80) - break; - - m->volcmd = VOLCMD_PANNING; - m->command = nEffect; - - if(m_nType & MOD_TYPE_S3M) - { - m->vol = m->param >> 1; - } - else - { - m->vol = (m->param >> 2) + 1; - } - - m->param = nParam; - return true; - } - } - } - - // Let's try it again by writing into the "other" effect column. - BYTE nNewEffect = CMD_NONE; - if(bIsVolumeEffect) - { - switch(nEffect) - { - case VOLCMD_PANNING: - nNewEffect = CMD_PANNING8; - if(m_nType & MOD_TYPE_S3M) - nParam <<= 1; - else - nParam = min(nParam << 2, 0xFF); - break; - case VOLCMD_VOLUME: - nNewEffect = CMD_VOLUME; - break; - } - } else - { - switch(nEffect) - { - case CMD_PANNING8: - nNewEffect = VOLCMD_PANNING; - if(m_nType & MOD_TYPE_S3M) - { - if(nParam <= 0x80) - nParam >>= 1; - else - nNewEffect = CMD_NONE; - } - else - { - nParam = (nParam >> 2) + 1; - } - break; - case CMD_VOLUME: - nNewEffect = CMD_VOLUME; - break; - } - } - if(nNewEffect != CMD_NONE) - { - if(TryWriteEffect(nPat, nRow, nNewEffect, nParam, !bIsVolumeEffect, nChn, bAllowMultipleEffects, allowRowChange, false) == true) return true; - } - } - - // Try in the next row if possible (this may also happen if we already retried) - if(allowRowChange == weTryNextRow && (nRow + 1 < Patterns[nPat].GetNumRows())) - { - return TryWriteEffect(nPat, nRow + 1, nEffect, nParam, bIsVolumeEffect, nChn, bAllowMultipleEffects, allowRowChange, bRetry); - } else if(allowRowChange == weTryPreviousRow && (nRow > 0)) - { - return TryWriteEffect(nPat, nRow - 1, nEffect, nParam, bIsVolumeEffect, nChn, bAllowMultipleEffects, allowRowChange, bRetry); - } - - return false; -} - - -// Try to convert a fx column command (*e) into a volume column command. +// Try to convert a fx column command (&effect) into a volume column command. // Returns true if successful. // Some commands can only be converted by losing some precision. // If moving the command into the volume column is more important than accuracy, use force = true. Modified: trunk/OpenMPT/soundlib/modcommand.h =================================================================== --- trunk/OpenMPT/soundlib/modcommand.h 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/modcommand.h 2012-06-15 21:48:47 UTC (rev 1300) @@ -118,61 +118,67 @@ // Volume Column commands -#define VOLCMD_NONE 0 -#define VOLCMD_VOLUME 1 -#define VOLCMD_PANNING 2 -#define VOLCMD_VOLSLIDEUP 3 -#define VOLCMD_VOLSLIDEDOWN 4 -#define VOLCMD_FINEVOLUP 5 -#define VOLCMD_FINEVOLDOWN 6 -#define VOLCMD_VIBRATOSPEED 7 -#define VOLCMD_VIBRATODEPTH 8 -#define VOLCMD_PANSLIDELEFT 9 -#define VOLCMD_PANSLIDERIGHT 10 -#define VOLCMD_TONEPORTAMENTO 11 -#define VOLCMD_PORTAUP 12 -#define VOLCMD_PORTADOWN 13 -#define VOLCMD_DELAYCUT 14 //currently unused -#define VOLCMD_OFFSET 15 //rewbs.volOff -#define MAX_VOLCMDS 16 +enum VolumeCommands +{ + VOLCMD_NONE = 0, + VOLCMD_VOLUME = 1, + VOLCMD_PANNING = 2, + VOLCMD_VOLSLIDEUP = 3, + VOLCMD_VOLSLIDEDOWN = 4, + VOLCMD_FINEVOLUP = 5, + VOLCMD_FINEVOLDOWN = 6, + VOLCMD_VIBRATOSPEED = 7, + VOLCMD_VIBRATODEPTH = 8, + VOLCMD_PANSLIDELEFT = 9, + VOLCMD_PANSLIDERIGHT = 10, + VOLCMD_TONEPORTAMENTO = 11, + VOLCMD_PORTAUP = 12, + VOLCMD_PORTADOWN = 13, + VOLCMD_DELAYCUT = 14, //currently unused + VOLCMD_OFFSET = 15, //rewbs.volOff + MAX_VOLCMDS = 16 +}; // Effect column commands -#define CMD_NONE 0 -#define CMD_ARPEGGIO 1 -#define CMD_PORTAMENTOUP 2 -#define CMD_PORTAMENTODOWN 3 -#define CMD_TONEPORTAMENTO 4 -#define CMD_VIBRATO 5 -#define CMD_TONEPORTAVOL 6 -#define CMD_VIBRATOVOL 7 -#define CMD_TREMOLO 8 -#define CMD_PANNING8 9 -#define CMD_OFFSET 10 -#define CMD_VOLUMESLIDE 11 -#define CMD_POSITIONJUMP 12 -#define CMD_VOLUME 13 -#define CMD_PATTERNBREAK 14 -#define CMD_RETRIG 15 -#define CMD_SPEED 16 -#define CMD_TEMPO 17 -#define CMD_TREMOR 18 -#define CMD_MODCMDEX 19 -#define CMD_S3MCMDEX 20 -#define CMD_CHANNELVOLUME 21 -#define CMD_CHANNELVOLSLIDE 22 -#define CMD_GLOBALVOLUME 23 -#define CMD_GLOBALVOLSLIDE 24 -#define CMD_KEYOFF 25 -#define CMD_FINEVIBRATO 26 -#define CMD_PANBRELLO 27 -#define CMD_XFINEPORTAUPDOWN 28 -#define CMD_PANNINGSLIDE 29 -#define CMD_SETENVPOSITION 30 -#define CMD_MIDI 31 -#define CMD_SMOOTHMIDI 32 //rewbs.smoothVST -#define CMD_DELAYCUT 33 -#define CMD_XPARAM 34 // -> CODE#0010 -> DESC="add extended parameter mechanism to pattern effects" -! NEW_FEATURE#0010 -#define CMD_NOTESLIDEUP 35 // IMF Gxy -#define CMD_NOTESLIDEDOWN 36 // IMF Hxy -#define MAX_EFFECTS 37 +enum EffectCommands +{ + CMD_NONE = 0, + CMD_ARPEGGIO = 1, + CMD_PORTAMENTOUP = 2, + CMD_PORTAMENTODOWN = 3, + CMD_TONEPORTAMENTO = 4, + CMD_VIBRATO = 5, + CMD_TONEPORTAVOL = 6, + CMD_VIBRATOVOL = 7, + CMD_TREMOLO = 8, + CMD_PANNING8 = 9, + CMD_OFFSET = 10, + CMD_VOLUMESLIDE = 11, + CMD_POSITIONJUMP = 12, + CMD_VOLUME = 13, + CMD_PATTERNBREAK = 14, + CMD_RETRIG = 15, + CMD_SPEED = 16, + CMD_TEMPO = 17, + CMD_TREMOR = 18, + CMD_MODCMDEX = 19, + CMD_S3MCMDEX = 20, + CMD_CHANNELVOLUME = 21, + CMD_CHANNELVOLSLIDE = 22, + CMD_GLOBALVOLUME = 23, + CMD_GLOBALVOLSLIDE = 24, + CMD_KEYOFF = 25, + CMD_FINEVIBRATO = 26, + CMD_PANBRELLO = 27, + CMD_XFINEPORTAUPDOWN = 28, + CMD_PANNINGSLIDE = 29, + CMD_SETENVPOSITION = 30, + CMD_MIDI = 31, + CMD_SMOOTHMIDI = 32, //rewbs.smoothVST + CMD_DELAYCUT = 33, + CMD_XPARAM = 34, // -> CODE#0010 -> DESC="add extended parameter mechanism to pattern effects" -! NEW_FEATURE#0010 + CMD_NOTESLIDEUP = 35, // IMF Gxy + CMD_NOTESLIDEDOWN = 36, // IMF Hxy + MAX_EFFECTS = 37 +}; Modified: trunk/OpenMPT/soundlib/pattern.cpp =================================================================== --- trunk/OpenMPT/soundlib/pattern.cpp 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/pattern.cpp 2012-06-15 21:48:47 UTC (rev 1300) @@ -232,6 +232,178 @@ } +// Write some kind of effect data to the pattern. Exact data to be written and write behaviour can be found in the EffectWriter object. +bool CPattern::WriteEffect(EffectWriter &settings) +//------------------------------------------------ +{ + // First, reject invalid parameters. + if(!m_ModCommands + || settings.row >= GetNumRows() + || (settings.channel >= GetNumChannels() && settings.channel != CHANNELINDEX_INVALID)) + { + return false; + } + + CHANNELINDEX scanChnMin = settings.channel, scanChnMax = settings.channel; + + // Scan all channels + if(settings.channel == CHANNELINDEX_INVALID) + { + scanChnMin = 0; + scanChnMax = GetNumChannels() - 1; + } + + ModCommand * const baseCommand = GetpModCommand(settings.row, scanChnMin); + ModCommand *m; + + // Scan channel(s) for same effect type - if an effect of the same type is already present, exit. + if(!settings.allowMultiple) + { + m = baseCommand; + for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) + { + if(!settings.isVolEffect && m->command == settings.command) + return true; + if(settings.isVolEffect && m->volcmd == settings.command) + return true; + } + } + + // Easy case: check if there's some space left to put the effect somewhere + m = baseCommand; + for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) + { + if(!settings.isVolEffect && m->command == CMD_NONE) + { + m->command = settings.command; + m->param = settings.param; + return true; + } + if(settings.isVolEffect && m->volcmd == VOLCMD_NONE) + { + m->volcmd = settings.command; + m->vol = settings.param; + return true; + } + } + + // Ok, apparently there's no space. If we haven't tried already, try to map it to the volume column or effect column instead. + if(settings.retry) + { + const bool isS3M = (GetSoundFile().GetType() & MOD_TYPE_S3M) != 0; + + // Move some effects that also work in the volume column, so there's place for our new effect. + if(!settings.isVolEffect) + { + m = baseCommand; + for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) + { + switch(m->command) + { + case CMD_VOLUME: + m->volcmd = VOLCMD_VOLUME; + m->vol = m->param; + m->command = settings.command; + m->param = settings.param; + return true; + + case CMD_PANNING8: + if(isS3M && settings.param > 0x80) + { + break; + } + + m->volcmd = VOLCMD_PANNING; + m->command = settings.command; + + if(isS3M) + { + m->vol = m->param >> 1; + } else + { + m->vol = (m->param >> 2) + 1; + } + + m->param = settings.param; + return true; + } + } + } + + // Let's try it again by writing into the "other" effect column. + uint8 newCommand = CMD_NONE, newParam = settings.param; + if(settings.isVolEffect) + { + // Convert volume effect to normal effect + switch(settings.command) + { + case VOLCMD_PANNING: + newCommand = CMD_PANNING8; + if(isS3M) + { + newParam <<= 1; + } else + { + newParam = min(settings.param << 2, 0xFF); + } + break; + case VOLCMD_VOLUME: + newCommand = CMD_VOLUME; + break; + } + } else + { + // Convert normal effect to volume effect + if(settings.command == CMD_PANNING8 && isS3M) + { + // This needs some manual fixing. + if(settings.param <= 0x80) + { + // Can't have surround in volume column, only normal panning + newCommand = VOLCMD_PANNING; + newParam >>= 1; + } + } else + { + newCommand = settings.command; + if(!ModCommand::ConvertVolEffect(newCommand, newParam, true)) + { + // No Success :( + newCommand = CMD_NONE; + } + } + } + + if(newCommand != CMD_NONE) + { + settings.command = newCommand; + settings.param = newParam; + settings.retry = false; + settings.isVolEffect = !settings.isVolEffect; + if(WriteEffect(settings)) + { + return true; + } + } + } + + // Try in the next row if possible (this may also happen if we already retried) + if(settings.retryMode == EffectWriter::rmTryNextRow && settings.row + 1 < GetNumRows()) + { + settings.row++; + settings.retry = true; + return WriteEffect(settings); + } else if(settings.retryMode == EffectWriter::rmTryPreviousRow && settings.row > 0) + { + settings.row--; + settings.retry = true; + return WriteEffect(settings); + } + + return false; +} + + //////////////////////////////////////////////////////////////////////// // // Static allocation / deallocation methods @@ -244,8 +416,9 @@ { try { - ModCommand *p = new ModCommand[rows * nchns]; - memset(p, 0, rows * nchns * sizeof(ModCommand)); + size_t patSize = rows * nchns; + ModCommand *p = new ModCommand[patSize]; + memset(p, 0, patSize * sizeof(ModCommand)); return p; } catch(MPTMemoryException) { @@ -257,7 +430,7 @@ void CPattern::FreePattern(ModCommand *pat) //----------------------------------------- { - if (pat) delete[] pat; + delete[] pat; } @@ -279,7 +452,7 @@ fwrite(&mc, sizeof(ModCommand), 1, f); } } - return false; + return false; } bool CPattern::ReadITPdata(const BYTE* const lpStream, DWORD& streamPos, const DWORD datasize, const DWORD dwMemLength) Modified: trunk/OpenMPT/soundlib/pattern.h =================================================================== --- trunk/OpenMPT/soundlib/pattern.h 2012-06-15 17:00:18 UTC (rev 1299) +++ trunk/OpenMPT/soundlib/pattern.h 2012-06-15 21:48:47 UTC (rev 1300) @@ -18,9 +18,11 @@ class CPatternContainer; class CSoundFile; +class EffectWriter; typedef ModCommand* PatternRow; + //============ class CPattern //============ @@ -91,7 +93,12 @@ // Patter name functions (for both CString and char[] arrays) - bool functions return true on success. bool SetName(const char *newName, size_t maxChars = MAX_PATTERNNAME); bool SetName(const CString newName) { m_PatternName = newName; return true; }; - bool GetName(char *buffer, size_t maxChars = MAX_PATTERNNAME) const; + template<size_t bufferSize> + bool GetName(char (&buffer)[bufferSize]) const + { + return GetName(buffer, bufferSize); + } + bool GetName(char *buffer, size_t maxChars) const; CString GetName() const { return m_PatternName; }; // Double number of rows @@ -100,6 +107,9 @@ // Halve number of rows bool Shrink(); + // Write some kind of effect data to the pattern + bool WriteEffect(EffectWriter &settings); + bool WriteITPdata(FILE* f) const; bool ReadITPdata(const BYTE* const lpStream, DWORD& streamPos, const DWORD datasize, const DWORD dwMemLength); //Parameters: @@ -150,3 +160,56 @@ void ReadModPattern(std::istream& iStrm, CPattern& patc, const size_t nSize = 0); void WriteModPattern(std::ostream& oStrm, const CPattern& patc); + + +// Class for conveniently writing an effect to the pattern. + +//================ +class EffectWriter +//================ +{ + friend class CPattern; + +public: + // Row advance mode + enum RetryMode + { + rmIgnore, // If effect can't be written, abort. + rmTryNextRow, // If effect can't be written, try next row. + rmTryPreviousRow, // If effect can't be written, try previous row. + }; + + // Constructors with effect commands + EffectWriter(EffectCommands cmd, ModCommand::PARAM value) : command(static_cast<uint8>(cmd)), param(value), isVolEffect(false) { Init(); } + EffectWriter(VolumeCommands cmd, ModCommand::VOL value) : command(static_cast<uint8>(cmd)), param(value), isVolEffect(true) { Init(); } + + // Additional constructors: + // Set row in which writing should start + EffectWriter &Row(ROWINDEX row) { this->row = row; return *this; } + // Set channel to which writing should be restricted to + EffectWriter &Channel(CHANNELINDEX chn) { channel = chn; return *this; } + // Allow multiple effects of the same kind to be written in the same row. + EffectWriter &AllowMultiple() { allowMultiple = true; return *this; } + // Set retry mode. + EffectWriter &Retry(RetryMode retryMode) { this->retryMode = retryMode; return *this; } + +protected: + uint8 command, param; + bool isVolEffect; + + ROWINDEX row; + CHANNELINDEX channel; + bool allowMultiple; + RetryMode retryMode; + bool retry; + + // Common data initialisation + void Init() + { + row = 0; + channel = CHANNELINDEX_INVALID; // Any channel + allowMultiple = false; // Stop if same type of effect is encountered + retryMode = rmIgnore; // If effect couldn't be written, abort. + retry = true; + } +}; \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-17 15:31:56
|
Revision: 1302 http://modplug.svn.sourceforge.net/modplug/?rev=1302&view=rev Author: saga-games Date: 2012-06-17 15:31:45 +0000 (Sun, 17 Jun 2012) Log Message: ----------- [Ref] Moved frequency / transpose conversion functions from CSoundFile to ModSample. [Ref] Added CSoundFile::AllocateInstrument which takes care of instrument initialisation and deleting old instrument. Modified Paths: -------------- trunk/OpenMPT/mptrack/Autotune.cpp trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/Dlsbank.cpp trunk/OpenMPT/soundlib/LOAD_DBM.CPP trunk/OpenMPT/soundlib/Load_gdm.cpp trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_mdl.cpp trunk/OpenMPT/soundlib/Load_mid.cpp trunk/OpenMPT/soundlib/Load_mt2.cpp trunk/OpenMPT/soundlib/Load_mtm.cpp trunk/OpenMPT/soundlib/Load_psm.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/ModSample.cpp trunk/OpenMPT/soundlib/ModSample.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/XMTools.cpp trunk/OpenMPT/soundlib/load_j2b.cpp trunk/OpenMPT/soundlib/pattern.h Modified: trunk/OpenMPT/mptrack/Autotune.cpp =================================================================== --- trunk/OpenMPT/mptrack/Autotune.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/mptrack/Autotune.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -193,6 +193,7 @@ vector<uint64> interpolatedHistogram(historyBins, 0); for(int i = 0; i < historyBins; i++) { + interpolatedHistogram[i] = autocorrHistogram[i]; const int kernelWidth = 4; for(int ki = kernelWidth; ki >= 0; ki--) { @@ -238,7 +239,7 @@ if((modType & (MOD_TYPE_XM | MOD_TYPE_MOD)) != 0) { - CSoundFile::FrequencyToTranspose(&sample); + sample.FrequencyToTranspose(); if((modType & MOD_TYPE_MOD) != 0) { sample.RelativeTone = 0; Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -122,14 +122,12 @@ CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); if(m_nInstrument > 0 && pSndFile && m_nInstrument <= pSndFile->GetNumInstruments() && pSndFile->Instruments[m_nInstrument] == nullptr) { - try + ModInstrument *instrument = pSndFile->AllocateInstrument(m_nInstrument); + if(instrument == nullptr) { - pSndFile->Instruments[m_nInstrument] = new ModInstrument(); - } catch(MPTMemoryException) - { return FALSE; } - m_pModDoc->InitializeInstrument(pSndFile->Instruments[m_nInstrument]); + m_pModDoc->InitializeInstrument(instrument); } InvalidateRect(NULL, FALSE); Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -530,7 +530,7 @@ if ((m_pSndFile) && (m_pSndFile->GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) && (m_nSample)) { const ModSample &sample = m_pSndFile->GetSample(m_nSample); - UINT nFreqHz = CSoundFile::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); + UINT nFreqHz = ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); wsprintf(pszText, "%ldHz", nFreqHz); return TRUE; } @@ -690,12 +690,12 @@ } //end rewbs.fix36944 // FineTune / C-4 Speed / BaseNote - int transp = 0; + int transp = 0; if (m_pSndFile->GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) { wsprintf(s, "%lu", sample.nC5Speed); m_EditFineTune.SetWindowText(s); - transp = CSoundFile::FrequencyToTranspose(sample.nC5Speed) >> 7; + transp = ModSample::FrequencyToTranspose(sample.nC5Speed) >> 7; } else { int ftune = ((int)sample.nFineTune); @@ -1047,7 +1047,7 @@ else { // save all samples - CString sPath = m_pSndFile->m_pModDoc->GetPathName(); + CString sPath = m_pSndFile->GetpModDoc()->GetPathName(); if(sPath.IsEmpty()) sPath = "untitled"; sPath += " - %sample_number% - "; @@ -2476,7 +2476,7 @@ if ((n > 0) && (n <= (m_pSndFile->GetType() == MOD_TYPE_S3M ? 65535 : 9999999)) && (n != (int)m_pSndFile->GetSample(m_nSample).nC5Speed)) { m_pSndFile->GetSample(m_nSample).nC5Speed = n; - int transp = CSoundFile::FrequencyToTranspose(n) >> 7; + int transp = ModSample::FrequencyToTranspose(n) >> 7; int basenote = 60 - transp; if (basenote < BASENOTE_MIN) basenote = BASENOTE_MIN; if (basenote >= BASENOTE_MAX) basenote = BASENOTE_MAX-1; @@ -2513,8 +2513,8 @@ if (m_pSndFile->m_nType & (MOD_TYPE_IT|MOD_TYPE_S3M|MOD_TYPE_MPT)) { - LONG ft = CSoundFile::FrequencyToTranspose(sample.nC5Speed) & 0x7F; - n = CSoundFile::TransposeToFrequency(n, ft); + LONG ft = ModSample::FrequencyToTranspose(sample.nC5Speed) & 0x7F; + n = ModSample::TransposeToFrequency(n, ft); if ((n > 0) && (n <= (m_pSndFile->GetType() == MOD_TYPE_S3M ? 65535 : 9999999)) && (n != (int)sample.nC5Speed)) { CHAR s[32]; @@ -3006,7 +3006,7 @@ if(d < m_nFinetuneStep) d = m_nFinetuneStep; d += (pos * m_nFinetuneStep); sample.nC5Speed = Clamp(d, 1u, 9999999u); // 9999999 is max. in Impulse Tracker - int transp = CSoundFile::FrequencyToTranspose(sample.nC5Speed) >> 7; + int transp = ModSample::FrequencyToTranspose(sample.nC5Speed) >> 7; int basenote = 60 - transp; if (basenote < BASENOTE_MIN) basenote = BASENOTE_MIN; if (basenote >= BASENOTE_MAX) basenote = BASENOTE_MAX-1; Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -737,13 +737,10 @@ if ((!m_SndFile.m_nInstruments) && (m_SndFile.GetType() & MOD_TYPE_XM)) { - try + if(m_SndFile.AllocateInstrument(1, 1)) { - m_SndFile.Instruments[1] = new ModInstrument(1); m_SndFile.m_nInstruments = 1; InitializeInstrument(m_SndFile.Instruments[1]); - } catch(MPTMemoryException) - { } } if (m_SndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)) @@ -1273,8 +1270,7 @@ { m_bsMultiRecordMask.reset(channel); m_bsMultiSplitRecordMask.reset(channel); - } - else + } else { m_bsMultiRecordMask.flip(channel); m_bsMultiSplitRecordMask.reset(channel); @@ -1288,8 +1284,7 @@ { m_bsMultiRecordMask.reset(channel); m_bsMultiSplitRecordMask.reset(channel); - } - else + } else { m_bsMultiSplitRecordMask.flip(channel); m_bsMultiRecordMask.reset(channel); @@ -1303,8 +1298,7 @@ { m_bsMultiRecordMask.reset(); m_bsMultiSplitRecordMask.reset(); - } - else + } else { m_bsMultiRecordMask.set(); m_bsMultiSplitRecordMask.set(); Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -320,17 +320,15 @@ const bool muted = IsSampleMuted(smp); MuteSample(smp, false); - try + ModInstrument *instrument = m_SndFile.AllocateInstrument(smp, smp); + if(instrument == nullptr) { - m_SndFile.Instruments[smp] = new ModInstrument(smp); - } catch(MPTMemoryException) - { ErrorBox(IDS_ERR_OUTOFMEMORY, CMainFrame::GetMainFrame()); return false; } - InitializeInstrument(m_SndFile.Instruments[smp]); - lstrcpyn(m_SndFile.Instruments[smp]->name, m_SndFile.m_szNames[smp], MAX_INSTRUMENTNAME); + InitializeInstrument(instrument); + lstrcpyn(instrument->name, m_SndFile.m_szNames[smp], MAX_INSTRUMENTNAME); MuteInstrument(smp, muted); } @@ -523,19 +521,17 @@ } } - ModInstrument *pIns; - try + CriticalSection cs; + + ModInstrument *pIns = m_SndFile.AllocateInstrument(newsmp); + if(pIns == nullptr) { - pIns = new ModInstrument(newsmp); - } catch(MPTMemoryException) - { + cs.Leave(); ErrorBox(IDS_ERR_OUTOFMEMORY, CMainFrame::GetMainFrame()); return INSTRUMENTINDEX_INVALID; } InitializeInstrument(pIns); - CriticalSection cs; - if (pDup) { *pIns = *pDup; Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -319,7 +319,7 @@ LONG lSampleRate = pSndFile->GetSample(m_nSample).nC5Speed; if (pSndFile->m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM)) { - lSampleRate = CSoundFile::TransposeToFrequency(pSndFile->GetSample(m_nSample).RelativeTone, pSndFile->GetSample(m_nSample).nFineTune); + lSampleRate = ModSample::TransposeToFrequency(pSndFile->GetSample(m_nSample).RelativeTone, pSndFile->GetSample(m_nSample).nFineTune); } if (!lSampleRate) lSampleRate = 8363; ULONG msec = ((ULONG)selLength * 1000) / lSampleRate; @@ -1308,7 +1308,7 @@ const char cOffsetChar = pSndFile->GetModSpecifications().GetEffectLetter(CMD_OFFSET); const bool bHasHighOffset = (pSndFile->TypeIsS3M_IT_MPT() || (pSndFile->GetType() == MOD_TYPE_XM)); - const char cHighOffsetChar = pSndFile->GetModSpecifications().GetEffectLetter((pSndFile->TypeIsS3M_IT_MPT()) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN); + const char cHighOffsetChar = pSndFile->GetModSpecifications().GetEffectLetter(static_cast<ModCommand::COMMAND>(pSndFile->TypeIsS3M_IT_MPT() ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN)); if(xHigh == 0) wsprintf(s, "Offset: %c%02X", cOffsetChar, xLow); @@ -1884,7 +1884,7 @@ pfmt->freqHz = sample.nC5Speed; if (pSndFile->m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM)) { - pfmt->freqHz = CSoundFile::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); + pfmt->freqHz = ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); } pfmt->channels = (sample.uFlags & CHN_STEREO) ? (WORD)2 : (WORD)1; pfmt->bitspersample = (sample.uFlags & CHN_16BIT) ? (WORD)16 : (WORD)8; Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp =================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -1583,7 +1583,7 @@ sFineTune+(60 + transpose - usUnityNote)*100); sample.nFineTune = (CHAR)(nBaseTune & 0x7F); sample.RelativeTone = (CHAR)(nBaseTune >> 7); - sample.nC5Speed = CSoundFile::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); + sample.TransposeToFrequency(); if (lVolume > 256) lVolume = 256; if (lVolume < 16) lVolume = 16; sample.nGlobalVol = (BYTE)(lVolume / 4); // 0-64 Modified: trunk/OpenMPT/soundlib/LOAD_DBM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-06-17 15:31:45 UTC (rev 1302) @@ -245,16 +245,12 @@ nsmp = BigEndianW(pih->sampleno); psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Samples[nsmp] : nullptr; - try + pIns = AllocateInstrument(iIns + 1, nsmp); + if(pIns == nullptr) { - pIns = new ModInstrument(nsmp); - } catch(MPTMemoryException) - { break; } - Instruments[iIns + 1] = pIns; - StringFixer::ReadString<StringFixer::maybeNullTerminated>(pIns->name, pih->name); if (psmp) { Modified: trunk/OpenMPT/soundlib/Load_gdm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_gdm.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_gdm.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -220,7 +220,7 @@ Samples[smp].nLoopStart = min(gdmSample.loopBegin, Samples[smp].nLength); // in samples Samples[smp].nLoopEnd = min(gdmSample.loopEnd - 1, Samples[smp].nLength); // dito - FrequencyToTranspose(&Samples[smp]); // set transpose + finetune for mod files + Samples[smp].FrequencyToTranspose(); // set transpose + finetune for mod files // Fix transpose + finetune for some rare cases where transpose is not C-5 (e.g. sample 4 in wander2.gdm) if(m_nType == MOD_TYPE_MOD) Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -492,16 +492,12 @@ //if(memcmp(imfins.ii10, "II10", 4) != 0) // return false; - try + pIns = AllocateInstrument(nIns + 1); + if(pIns == nullptr) { - pIns = new ModInstrument(); - } catch(MPTMemoryException) - { continue; } - Instruments[nIns + 1] = pIns; - StringFixer::ReadString<StringFixer::nullTerminated>(pIns->name, imfins.name); if(imfins.smpnum) Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -730,13 +730,10 @@ { if ((inspos[nins] > 0) && (inspos[nins] <= dwMemLength - (itHeader.cmwt < 0x200 ? sizeof(ITOldInstrument) : sizeof(ITInstrument)))) { - try + ModInstrument *instrument = AllocateInstrument(nins + 1); + if(instrument != nullptr) { - Instruments[nins + 1] = new ModInstrument(); - ITInstrToMPT(lpStream + inspos[nins], Instruments[nins + 1], itHeader.cmwt, dwMemLength - inspos[nins]); - } catch(MPTMemoryException) - { - continue; + ITInstrToMPT(lpStream + inspos[nins], instrument, itHeader.cmwt, dwMemLength - inspos[nins]); } } } Modified: trunk/OpenMPT/soundlib/Load_mdl.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mdl.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_mdl.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -414,14 +414,11 @@ if (!Instruments[nins]) { UINT note = 12; - try + ModInstrument *pIns = AllocateInstrument(nins); + if(pIns == nullptr) { - Instruments[nins] = new ModInstrument(); - } catch(MPTMemoryException) - { break; } - ModInstrument *pIns = Instruments[nins]; // 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); @@ -468,13 +465,7 @@ } for (j=1; j<=m_nInstruments; j++) if (!Instruments[j]) { - try - { - Instruments[j] = new ModInstrument(); - } catch(MPTMemoryException) - { - } - + AllocateInstrument(j); } break; // VE: Volume Envelope Modified: trunk/OpenMPT/soundlib/Load_mid.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mid.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_mid.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -394,17 +394,14 @@ } if ((m_nInstruments + 1 >= MAX_INSTRUMENTS) || (m_nSamples + 1 >= MAX_SAMPLES)) return 0; - try + pIns = AllocateInstrument(m_nInstruments + 1); + if(pIns == nullptr) { - pIns = new ModInstrument(); - } catch(MPTMemoryException) - { return 0; } m_nSamples++; m_nInstruments++; - Instruments[m_nInstruments] = pIns; pIns->wMidiBank = nBank; pIns->nMidiProgram = nProgram; pIns->nMidiChannel = nChannel; Modified: trunk/OpenMPT/soundlib/Load_mt2.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mt2.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_mt2.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -412,13 +412,10 @@ ModInstrument *pIns = NULL; if (iIns <= m_nInstruments) { - try + pIns = AllocateInstrument(iIns); + if(pIns != nullptr) { - pIns = new ModInstrument(); - Instruments[iIns] = pIns; StringFixer::ReadString<StringFixer::maybeNullTerminated>(pIns->name, pmi->szName); - } catch(MPTMemoryException) - { } } #ifdef MT2DEBUG @@ -540,9 +537,9 @@ psmp->nC5Speed = pms->dwFrequency; psmp->nLoopStart = pms->dwLoopStart; psmp->nLoopEnd = pms->dwLoopEnd; - FrequencyToTranspose(psmp); + psmp->FrequencyToTranspose(); psmp->RelativeTone -= pms->nBaseNote - 49; - psmp->nC5Speed = TransposeToFrequency(psmp->RelativeTone, psmp->nFineTune); + psmp->TransposeToFrequency(); if (pms->nQuality == 2) { psmp->uFlags |= CHN_16BIT; psmp->nLength >>= 1; } if (pms->nChannels == 2) { psmp->nLength >>= 1; } if (pms->nLoop == 1) psmp->uFlags |= CHN_LOOP; Modified: trunk/OpenMPT/soundlib/Load_mtm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mtm.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_mtm.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -90,7 +90,7 @@ Samples[i].nLoopEnd >>= 1; } Samples[i].nPan = 128; - Samples[i].nC5Speed = TransposeToFrequency(0, Samples[i].nFineTune); + Samples[i].nC5Speed = ModSample::TransposeToFrequency(0, Samples[i].nFineTune); } dwMemPos += 37; } Modified: trunk/OpenMPT/soundlib/Load_psm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_psm.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_psm.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -1046,8 +1046,8 @@ // 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.FrequencyToTranspose(); + mptSmp.nC5Speed = ModSample::TransposeToFrequency(mptSmp.RelativeTone + (finetune >> 4) - 7, MOD2XMFineTune(finetune & 0x0F)); mptSmp.nVolume = volume << 2; mptSmp.nGlobalVol = 256; Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -359,7 +359,7 @@ c5speed = mptSmp.nC5Speed; } else { - c5speed = CSoundFile::TransposeToFrequency(mptSmp.RelativeTone, mptSmp.nFineTune); + c5speed = ModSample::TransposeToFrequency(mptSmp.RelativeTone, mptSmp.nFineTune); } magic = idSCRS; Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -362,11 +362,8 @@ memcpy(&insHeader, lpStream + dwMemPos, min(sizeof(XMInstrumentHeader), insHeaderSize)); dwMemPos += insHeaderSize; - try + if(AllocateInstrument(instr) == nullptr) { - Instruments[instr] = new ModInstrument(); - } catch(MPTMemoryException) - { continue; } Modified: trunk/OpenMPT/soundlib/ModSample.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSample.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/ModSample.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -20,12 +20,12 @@ // Convert between frequency and transpose values if necessary. if ((!(toType & (MOD_TYPE_MOD | MOD_TYPE_XM))) && (fromType & (MOD_TYPE_MOD | MOD_TYPE_XM))) { - nC5Speed = CSoundFile::TransposeToFrequency(RelativeTone, nFineTune); + TransposeToFrequency(); RelativeTone = 0; nFineTune = 0; } else if((toType & (MOD_TYPE_MOD | MOD_TYPE_XM)) && (!(fromType & (MOD_TYPE_MOD | MOD_TYPE_XM)))) { - CSoundFile::FrequencyToTranspose(this); + FrequencyToTranspose(); if(toType & MOD_TYPE_MOD) { RelativeTone = 0; @@ -122,7 +122,7 @@ { uint32 rate; if(type & (MOD_TYPE_MOD | MOD_TYPE_XM)) - rate = CSoundFile::TransposeToFrequency(RelativeTone, nFineTune); + rate = TransposeToFrequency(RelativeTone, nFineTune); else rate = nC5Speed; return (rate > 0) ? rate : 8363; @@ -151,4 +151,96 @@ { CSoundFile::FreeSample(pSample); pSample = nullptr; +} + + +///////////////////////////////////////////////////////////// +// Transpose <-> Frequency conversions + +// returns 8363*2^((transp*128+ftune)/(12*128)) +uint32 ModSample::TransposeToFrequency(int transpose, int finetune) +//----------------------------------------------------------------- +{ + // return (unsigned int) (8363.0 * pow(2, (transp * 128.0 + ftune) / 1536.0)); + const float _fbase = 8363; + const float _factor = 1.0f / (12.0f * 128.0f); + int result; + uint32 freq; + + transpose = (transpose << 7) + finetune; + _asm + { + fild transpose + fld _factor + fmulp st(1), st(0) + fist result + fisub result + f2xm1 + fild result + fld _fbase + fscale + fstp st(1) + fmul st(1), st(0) + faddp st(1), st(0) + fistp freq + } + uint32 derr = freq % 11025; + if(derr <= 8) freq -= derr; + if(derr >= 11015) freq += 11025 - derr; + derr = freq % 1000; + if(derr <= 5) freq -= derr; + if(derr >= 995) freq += 1000 - derr; + return freq; +} + + +void ModSample::TransposeToFrequency() +//------------------------------------ +{ + nC5Speed = TransposeToFrequency(RelativeTone, nFineTune); +} + + +// returns 12*128*log2(freq/8363) +int ModSample::FrequencyToTranspose(uint32 freq) +//---------------------------------------------- +{ + // return (int) (1536.0 * (log(freq / 8363.0) / log(2))); + + const float _f1_8363 = 1.0f / 8363.0f; + const float _factor = 128 * 12; + int result; + + if(!freq) + { + return 0; + } + + _asm + { + fld _factor + fild freq + fld _f1_8363 + fmulp st(1), st(0) + fyl2x + fistp result + } + return result; +} + + +void ModSample::FrequencyToTranspose() +//------------------------------------ +{ + int f2t = FrequencyToTranspose(nC5Speed); + int transpose = f2t >> 7; + int finetune = f2t & 0x7F; //0x7F == 111 1111 + if(finetune > 80) // XXX Why is this 80? + { + transpose++; + finetune -= 128; + } + Limit(transpose, -127, 127); + RelativeTone = static_cast<int8>(transpose); + nFineTune = static_cast<int8>(finetune); } \ No newline at end of file Modified: trunk/OpenMPT/soundlib/ModSample.h =================================================================== --- trunk/OpenMPT/soundlib/ModSample.h 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/ModSample.h 2012-06-17 15:31:45 UTC (rev 1302) @@ -58,4 +58,10 @@ size_t AllocateSample(); void FreeSample(); + + // Transpose <-> Frequency conversions + static uint32 TransposeToFrequency(int transpose, int finetune = 0); + void TransposeToFrequency(); + static int FrequencyToTranspose(uint32 freq); + void FrequencyToTranspose(); }; Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -401,7 +401,7 @@ if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) format.freqHz = LittleEndian(sample.nC5Speed); else - format.freqHz = LittleEndian(TransposeToFrequency(sample.RelativeTone, sample.nFineTune)); + format.freqHz = LittleEndian(ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune)); format.channels = LittleEndianW(sample.GetNumChannels()); format.bitspersample = LittleEndianW(sample.GetElementarySampleSize() * 8); format.samplesize = LittleEndianW(sample.GetBytesPerSample()); @@ -672,13 +672,13 @@ sample.nVibSweep = psh->vibrato_sweep; sample.nVibDepth = psh->vibrato_depth; sample.nVibRate = psh->vibrato_rate/4; - CSoundFile::FrequencyToTranspose(&sample); + sample.FrequencyToTranspose(); sample.RelativeTone += static_cast<uint8>(84 - PatchFreqToNote(psh->root_freq)); if(psh->scale_factor) { sample.RelativeTone = static_cast<uint8>(sample.RelativeTone - psh->scale_frequency - 60); } - sample.nC5Speed = CSoundFile::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); + sample.TransposeToFrequency(); SampleIO sampleIO( SampleIO::_8bit, @@ -1200,10 +1200,10 @@ return SwapBytesBE(l); } - ChunkIdentifiers GetID() const + id_type GetID() const { uint32 i = id; - return static_cast<ChunkIdentifiers>(SwapBytesBE(i)); + return static_cast<id_type>(SwapBytesBE(i)); } }; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -1373,85 +1373,6 @@ } -///////////////////////////////////////////////////////////// -// Transpose <-> Frequency conversions - -// returns 8363*2^((transp*128+ftune)/(12*128)) -DWORD CSoundFile::TransposeToFrequency(int transp, int ftune) -//----------------------------------------------------------- -{ - // return (unsigned int) (8363.0 * pow(2, (transp * 128.0 + ftune) / 1536.0)); - const float _fbase = 8363; - const float _factor = 1.0f/(12.0f*128.0f); - int result; - DWORD freq; - - transp = (transp << 7) + ftune; - _asm { - fild transp - fld _factor - fmulp st(1), st(0) - fist result - fisub result - f2xm1 - fild result - fld _fbase - fscale - fstp st(1) - fmul st(1), st(0) - faddp st(1), st(0) - fistp freq - } - UINT derr = freq % 11025; - if (derr <= 8) freq -= derr; - if (derr >= 11015) freq += 11025-derr; - derr = freq % 1000; - if (derr <= 5) freq -= derr; - if (derr >= 995) freq += 1000-derr; - return freq; -} - - -// returns 12*128*log2(freq/8363) -int CSoundFile::FrequencyToTranspose(DWORD freq) -//---------------------------------------------- -{ - // return (int) (1536.0 * (log(freq / 8363.0) / log(2))); - - const float _f1_8363 = 1.0f / 8363.0f; - const float _factor = 128 * 12; - LONG result; - - if (!freq) return 0; - _asm { - fld _factor - fild freq - fld _f1_8363 - fmulp st(1), st(0) - fyl2x - fistp result - } - return result; -} - - -void CSoundFile::FrequencyToTranspose(ModSample *psmp) -//---------------------------------------------------- -{ - int f2t = FrequencyToTranspose(psmp->nC5Speed); - int transp = f2t >> 7; - int ftune = f2t & 0x7F; //0x7F == 111 1111 - if (ftune > 80) // XXX Why is this 80? - { - transp++; - ftune -= 128; - } - Limit(transp, -127, 127); - psmp->RelativeTone = static_cast<int8>(transp); - psmp->nFineTune = static_cast<int8>(ftune); -} - - void CSoundFile::CheckCPUUsage(UINT nCPU) //--------------------------------------- { @@ -2022,6 +1943,26 @@ } +ModInstrument *CSoundFile::AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample) +//---------------------------------------------------------------------------------------------- +{ + if(instr == 0 || instr >= MAX_INSTRUMENTS) + { + return nullptr; + } + + delete Instruments[instr]; + + try + { + return (Instruments[instr] = new ModInstrument(assignedSample)); + } catch(MPTMemoryException) + { + return (Instruments[instr] = nullptr); + } +} + + // Set up channel panning and volume suitable for MOD + similar files. If the current mod type is not MOD, bForceSetup has to be set to true. void CSoundFile::SetupMODPanning(bool bForceSetup) //------------------------------------------------ Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-06-17 15:31:45 UTC (rev 1302) @@ -649,20 +649,16 @@ DWORD CutOffToFrequency(UINT nCutOff, int flt_modifier=256) const; // [0-127] => [1-10KHz] #ifdef MODPLUG_TRACKER void ProcessMidiOut(CHANNELINDEX nChn); -#endif +#endif // MODPLUG_TRACKER void ApplyGlobalVolume(int SoundBuffer[], int RearBuffer[], long lTotalSampleCount); - // Static helper functions -public: - static DWORD TransposeToFrequency(int transp, int ftune=0); - static int FrequencyToTranspose(DWORD freq); - static void FrequencyToTranspose(ModSample *psmp); - // System-Dependant functions public: static LPSTR AllocateSample(UINT nbytes); static void FreeSample(void *p); + ModInstrument *AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample = 0); + // WAV export static UINT Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lmax24, DWORD dwByteInc); Modified: trunk/OpenMPT/soundlib/XMTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/XMTools.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/XMTools.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -345,7 +345,7 @@ relnote = mptSmp.RelativeTone; } else { - int f2t = CSoundFile::FrequencyToTranspose(mptSmp.nC5Speed); + int f2t = ModSample::FrequencyToTranspose(mptSmp.nC5Speed); relnote = (int8)(f2t >> 7); finetune = (int8)(f2t & 0x7F); } Modified: trunk/OpenMPT/soundlib/load_j2b.cpp =================================================================== --- trunk/OpenMPT/soundlib/load_j2b.cpp 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/load_j2b.cpp 2012-06-17 15:31:45 UTC (rev 1302) @@ -824,23 +824,17 @@ continue; } - const INSTRUMENTINDEX nIns = instrHeader.index + 1; - if(nIns >= MAX_INSTRUMENTS) + const INSTRUMENTINDEX instr = instrHeader.index + 1; + if(instr >= MAX_INSTRUMENTS) continue; - if(Instruments[nIns] != nullptr) - delete Instruments[nIns]; - - try + ModInstrument *pIns = AllocateInstrument(instr); + if(pIns == nullptr) { - Instruments[nIns] = new ModInstrument(); - } catch(MPTMemoryException) - { continue; } - ModInstrument *pIns = Instruments[nIns]; - m_nInstruments = max(m_nInstruments, nIns); + m_nInstruments = max(m_nInstruments, instr); instrHeader.ConvertToMPT(*pIns, m_nSamples); @@ -895,17 +889,11 @@ if(instr >= MAX_INSTRUMENTS) continue; - if(Instruments[instr] != nullptr) - delete Instruments[instr]; - - try + ModInstrument *pIns = AllocateInstrument(instr); + if(pIns == nullptr) { - Instruments[instr] = new ModInstrument(); - } catch(MPTMemoryException) - { continue; } - ModInstrument *pIns = Instruments[instr]; m_nInstruments = max(m_nInstruments, instr); instrHeader.ConvertToMPT(*pIns, m_nSamples); Modified: trunk/OpenMPT/soundlib/pattern.h =================================================================== --- trunk/OpenMPT/soundlib/pattern.h 2012-06-15 22:01:22 UTC (rev 1301) +++ trunk/OpenMPT/soundlib/pattern.h 2012-06-17 15:31:45 UTC (rev 1302) @@ -92,12 +92,18 @@ // Patter name functions (for both CString and char[] arrays) - bool functions return true on success. bool SetName(const char *newName, size_t maxChars = MAX_PATTERNNAME); + template<size_t bufferSize> + bool SetName(const char (&buffer)[bufferSize]) + { + return SetName(buffer, bufferSize); + } bool SetName(const CString newName) { m_PatternName = newName; return true; }; + template<size_t bufferSize> bool GetName(char (&buffer)[bufferSize]) const { - return GetName(buffer, bufferSize); - } + return GetName(buffer, bufferSize); + } bool GetName(char *buffer, size_t maxChars) const; CString GetName() const { return m_PatternName; }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-18 00:43:05
|
Revision: 1303 http://modplug.svn.sourceforge.net/modplug/?rev=1303&view=rev Author: saga-games Date: 2012-06-18 00:42:57 +0000 (Mon, 18 Jun 2012) Log Message: ----------- [Fix] Rewrote AMS (Velvet Studio) loader... Old one was commented out because it basically crashed on almost all VS modules. [Fix] Unbreak creating instruments from sample editor [Mod] OpenMPT: Version is now 1.20.01.08 Modified Paths: -------------- trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Load_ams.cpp trunk/OpenMPT/soundlib/Loaders.h trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Tables.cpp trunk/OpenMPT/soundlib/modcommand.cpp Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2012-06-18 00:42:57 UTC (rev 1303) @@ -523,7 +523,7 @@ CriticalSection cs; - ModInstrument *pIns = m_SndFile.AllocateInstrument(newsmp); + ModInstrument *pIns = m_SndFile.AllocateInstrument(newins, newsmp); if(pIns == nullptr) { cs.Leave(); @@ -542,8 +542,6 @@ // -! NEW_FEATURE#0023 } - m_SndFile.Instruments[newins] = pIns; - SetModified(); return newins; Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/mptrack/version.h 2012-06-18 00:42:57 UTC (rev 1303) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 07 +#define VER_MINORMINOR 08 //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_ams.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/Load_ams.cpp 2012-06-18 00:42:57 UTC (rev 1303) @@ -49,8 +49,8 @@ // Callback function for reading text -void Convert_AMS_Text_Chars(char &c) -//---------------------------------- +void ConvertAMSTextChars(char &c) +//------------------------------- { switch((unsigned char)c) { @@ -83,7 +83,7 @@ || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples >= MAX_SAMPLES) || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS)) { - return ReadAMS2(lpStream, dwMemLength); + return false; } dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra; if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) >= dwMemLength) return false; @@ -167,7 +167,7 @@ if (dwMemPos + tmp >= dwMemLength) return true; if (tmp) { - ReadMessage(lpStream + dwMemPos, tmp, leCR, &Convert_AMS_Text_Chars); + ReadMessage(lpStream + dwMemPos, tmp, leCR, &ConvertAMSTextChars); } dwMemPos += tmp; @@ -295,314 +295,712 @@ ///////////////////////////////////////////////////////////////////// -// AMS (Velvet Studio) 2.2 loader +// AMS (Velvet Studio) 2.1 / 2.2 loader -#pragma pack(push, 1) +#pragma pack(1) -typedef struct AMS2FILEHEADER +// AMS2 File Header +struct AMS2FileHeader { - DWORD dwHdr1; // AMShdr - WORD wHdr2; - BYTE b1A; // 0x1A - BYTE titlelen; // 30-bytes max - CHAR szTitle[30]; // [titlelen] -} AMS2FILEHEADER; + enum FileFlags + { + linearSlides = 0x40, + }; -typedef struct AMS2SONGHEADER + uint16 format; // Version of format (Hi = MainVer, Low = SubVer e.g. 0202 = 2.2) + uint8 numIns; // Nr of Instruments (0-255) + uint16 numPats; // Nr of Patterns (1-1024) + uint16 numOrds; // Nr of Positions (1-65535) + // Rest of header differs between format revision 2.01 and 2.02 + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(format); + SwapBytesLE(numPats); + SwapBytesLE(numOrds); + }; +}; + + +// AMS2 Instument Envelope +struct AMS2Envelope { - WORD version; - BYTE instruments; - WORD patterns; - WORD orders; - WORD bpm; - BYTE speed; - BYTE channels; - BYTE commands; - BYTE rows; - WORD flags; -} AMS2SONGHEADER; + uint8 speed; // Envelope speed + uint8 sustainPoint; // Envelope sustain point + uint8 loopStart; // Envelope loop Start + uint8 loopEnd; // Envelope loop End + uint8 numPoints; // Envelope length -typedef struct AMS2INSTRUMENT + // Read envelope and do partial conversion. + void ConvertToMPT(InstrumentEnvelope &mptEnv, FileReader &file) + { + file.Read(*this); + + // Read envelope points + struct + { + uint8 data[64][3]; + } env; + file.ReadStructPartial(env, numPoints * 3); + + if(numPoints <= 1) + { + // This is not an envelope. + return; + } + + STATIC_ASSERT(MAX_ENVPOINTS >= CountOf(env.data)); + mptEnv.nNodes = Util::Min(numPoints, uint8(CountOf(env.data))); + mptEnv.nLoopStart = loopStart; + mptEnv.nLoopEnd = loopEnd; + mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint; + + for(size_t i = 0; i < mptEnv.nNodes; i++) + { + if(i != 0) + { + mptEnv.Ticks[i] = mptEnv.Ticks[i - 1] + Util::Max(1, env.data[i][0] | ((env.data[i][1] & 0x01) << 8)); + } + mptEnv.Values[i] = env.data[i][2]; + } + } +}; + + +// AMS2 Instrument Data +struct AMS2Instrument { - BYTE samples; - BYTE notemap[NOTE_MAX]; -} AMS2INSTRUMENT; + enum EnvelopeFlags + { + envLoop = 0x01, + envSustain = 0x02, + envEnabled = 0x04, + + // Flag shift amounts + volEnvShift = 0, + panEnvShift = 1, + vibEnvShift = 2, -typedef struct AMS2ENVELOPE + vibAmpMask = 0x3000, + vibAmpShift = 12, + fadeOutMask = 0xFFF, + }; + + uint8 shadowInstr; // Shadow Instrument. If non-zero, the value=the shadowed inst. + uint16 vibampFadeout; // Vib.Amplify + Volume fadeout in one variable! + uint16 envFlags; // See EnvelopeFlags + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(vibampFadeout); + SwapBytesLE(envFlags); + } + + void ApplyFlags(InstrumentEnvelope &mptEnv, EnvelopeFlags shift) const + { + const uint8 flags = envFlags >> (shift * 3); + if(flags & envEnabled) mptEnv.dwFlags |= ENV_ENABLED; + if(flags & envLoop) mptEnv.dwFlags |= ENV_LOOP; + if(flags & envSustain) mptEnv.dwFlags |= ENV_SUSTAIN; + + // "Break envelope" should stop the envelope loop when encountering a note-off... We can only use the sustain loop to emulate this behaviour. + if(!(flags & envSustain) && (flags & envLoop) != 0 && (flags & (1 << (9 - shift * 2))) != 0) + { + mptEnv.nSustainStart = mptEnv.nLoopStart; + mptEnv.nSustainEnd = mptEnv.nLoopEnd; + mptEnv.dwFlags |= ENV_SUSTAIN; + mptEnv.dwFlags &= ~ENV_LOOP; + } + } + +}; + + +// AMS2 Sample Header +struct AMS2SampleHeader { - BYTE speed; - BYTE sustain; - BYTE loopbegin; - BYTE loopend; - BYTE points; - BYTE info[3]; -} AMS2ENVELOPE; + enum SampleFlags + { + smpPacked = 0x03, + smp16Bit = 0x04, + smpLoop = 0x08, + smpBidiLoop = 0x10, + }; -typedef struct AMS2SAMPLE + uint32 length; + uint32 loopStart; + uint32 loopEnd; + uint16 sampledRate; // Whyyyy? + uint8 panFinetune; // High nibble = pan position, low nibble = finetune value + uint16 c4speed; // Why is all of this so redundant? + int8 relativeTone; // q.e.d. + uint8 volume; // 0...127 + uint8 flags; // See SampleFlags + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(sampledRate); + SwapBytesLE(c4speed); + } + + // Convert sample header to OpenMPT's internal format. + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + + mptSmp.nLength = length; + mptSmp.nLoopStart = Util::Min(loopStart, length); + mptSmp.nLoopEnd = Util::Min(loopEnd, length); + + mptSmp.nC5Speed = c4speed * 2; + if(!mptSmp.nC5Speed) + { + mptSmp.nC5Speed = 8363 * 2; + } + // Why, oh why, does this format need a c5speed and transpose/finetune at the same time... + uint32 newC4speed = ModSample::TransposeToFrequency(relativeTone, MOD2XMFineTune(panFinetune & 0x0F)); + mptSmp.nC5Speed = (mptSmp.nC5Speed * newC4speed) / 8363; + + mptSmp.nVolume = (Util::Min(uint8(127), volume) * 256 + 64) / 127; + if(panFinetune & 0xF0) + { + mptSmp.nPan = (panFinetune & 0xF0); + mptSmp.uFlags = CHN_PANNING; + } + + if(flags & smp16Bit) + { + mptSmp.uFlags |= CHN_16BIT; + } + if((flags & smpLoop) && mptSmp.nLoopStart < mptSmp.nLoopEnd) + { + mptSmp.uFlags |= CHN_LOOP; + if(flags & smpBidiLoop) + { + mptSmp.uFlags |= CHN_PINGPONGLOOP; + } + } + } +}; + + +// AMS2 Song Description Header +struct AMS2Description { - DWORD length; - DWORD loopstart; - DWORD loopend; - WORD frequency; - BYTE finetune; - WORD nC5Speed; - CHAR transpose; - BYTE volume; - BYTE flags; -} AMS2SAMPLE; + uint32 packedLen; // Including header + uint32 unpackedLen; + uint8 packRoutine; // 01 + uint8 preProcessing; // None! + uint8 packingMethod; // RLE + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(packedLen); + SwapBytesLE(unpackedLen); + } +}; -#pragma pack(pop) +#pragma pack() -bool CSoundFile::ReadAMS2(LPCBYTE /*lpStream*/, DWORD /*dwMemLength*/) -//------------------------------------------------------------ + +// Read variable-length AMS string (we ignore the maximum text length specified by the AMS specs and accept any length). +template<size_t destSize> +bool ReadAMSString(char (&destBuffer)[destSize], FileReader &file) +//---------------------------------------------------------------- { - return false; -#if 0 - const AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream; - AMS2SONGHEADER *psh; - DWORD dwMemPos; - BYTE smpmap[16]; - BYTE packedsamples[MAX_SAMPLES]; + const size_t length = file.ReadUint8(); + return file.ReadString<StringFixer::spacePadded>(destBuffer, length); +} - if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264) - || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return false; - dwMemPos = pfh->titlelen + 8; - psh = (AMS2SONGHEADER *)(lpStream + dwMemPos); - if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments) - || (psh->instruments >= MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return false; - dwMemPos += sizeof(AMS2SONGHEADER); - if (pfh->titlelen) + +bool CSoundFile::ReadAMS2(FileReader &file) +//----------------------------------------- +{ + file.Rewind(); + + AMS2FileHeader fileHeader; + if(!file.ReadMagic("AMShdr\x1A") + || !ReadAMSString(m_szNames[0], file) + || !file.ReadConvertEndianness(fileHeader)) { - memcpy(m_szNames[0], pfh->szTitle, pfh->titlelen); - StringFixer::SpaceToNullStringFixed(m_szNames[0], pfh->titlelen); + return false; } - m_nType = MOD_TYPE_AMS; + + uint16 headerFlags; + if(fileHeader.format == 0x202) + { + m_nDefaultTempo = Util::Max(uint8(32), static_cast<uint8>(file.ReadUint16LE() >> 8)); // 16.16 Tempo + m_nDefaultSpeed = Util::Max(uint8(1), file.ReadUint8()); + file.Skip(3); // Default values for pattern editor + headerFlags = file.ReadUint16LE(); + } else if(fileHeader.format == 0x201) + { + m_nDefaultTempo = Util::Max(uint8(32), file.ReadUint8()); + m_nDefaultSpeed = Util::Max(uint8(1), file.ReadUint8()); + headerFlags = file.ReadUint8(); + } else + { + return false; + } + + m_nType = MOD_TYPE_AMS2; + m_dwSongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS | ((headerFlags & AMS2FileHeader::linearSlides) ? SONG_LINEARSLIDES : 0); + m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; + m_nSamplePreAmp = m_nVSTiVolume = 48; + m_nInstruments = fileHeader.numIns; m_nChannels = 32; - m_nDefaultTempo = psh->bpm >> 8; - m_nDefaultSpeed = psh->speed; - m_nInstruments = psh->instruments; - m_nSamples = 0; - if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES; - for (UINT nIns=1; nIns<=m_nInstruments; nIns++) + + // Instruments + vector<SAMPLEINDEX> firstSample; // First sample of instrument + vector<uint16> sampleSettings; // Shadow sample map... Lo byte = Instrument, Hi byte, lo nibble = Sample index in instrument, Hi byte, hi nibble = Sample pack status + enum { - UINT insnamelen = lpStream[dwMemPos]; - CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1); - dwMemPos += insnamelen + 1; - AMS2INSTRUMENT *pSmp = (AMS2INSTRUMENT *)(lpStream + dwMemPos); - dwMemPos += sizeof(AMS2INSTRUMENT); - if (dwMemPos + 1024 >= dwMemLength) return TRUE; - AMS2ENVELOPE *volenv, *panenv, *pitchenv; - volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); - dwMemPos += 5 + volenv->points*3; - panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); - dwMemPos += 5 + panenv->points*3; - pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); - dwMemPos += 5 + pitchenv->points*3; - ModInstrument *pIns; - try + instrIndexMask = 0xFF, // Shadow instrument + sampleIndexMask = 0x7F00, // Sample index in instrument + sampleIndexShift = 8, + packStatusMask = 0x8000, // If bit is set, sample is packed + }; + + for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) + { + ModInstrument *instrument = AllocateInstrument(ins); + if(instrument == nullptr + || !ReadAMSString(instrument->name, file)) { - pIns = new ModInstrument(); - } catch(MPTMemoryException) - { - return true; + return false; } - MemsetZero(smpmap); + uint8 numSamples = file.ReadUint8(); + uint8 sampleAssignment[120]; - for (UINT ismpmap=0; ismpmap<pSmp->samples; ismpmap++) + if(numSamples == 0 + || !file.ReadArray(sampleAssignment)) { - if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break; - m_nSamples++; - smpmap[ismpmap] = m_nSamples; + continue; } - Instruments[nIns] = pIns; - if (insnamelen) + STATIC_ASSERT(CountOf(instrument->Keyboard) >= CountOf(sampleAssignment)); + for(size_t i = 0; i < 120; i++) { - if (insnamelen > 31) insnamelen = 31; - memcpy(pIns->name, pinsname, insnamelen); - pIns->name[insnamelen] = 0; + instrument->Keyboard[i] = sampleAssignment[i] + GetNumSamples() + 1; } - for (UINT inotemap=0; inotemap<NOTE_MAX; inotemap++) + + AMS2Envelope volEnv, panEnv, vibratoEnv; + volEnv.ConvertToMPT(instrument->VolEnv, file); + panEnv.ConvertToMPT(instrument->PanEnv, file); + vibratoEnv.ConvertToMPT(instrument->PitchEnv, file); + + AMS2Instrument instrHeader; + file.ReadConvertEndianness(instrHeader); + instrument->nFadeOut = (instrHeader.vibampFadeout & AMS2Instrument::fadeOutMask) * 2; + const uint8 vibAmp = 1 + ((instrHeader.vibampFadeout & AMS2Instrument::vibAmpMask) >> AMS2Instrument::vibAmpShift); // "Close enough" + + instrHeader.ApplyFlags(instrument->VolEnv, AMS2Instrument::volEnvShift); + instrHeader.ApplyFlags(instrument->PanEnv, AMS2Instrument::panEnvShift); + instrHeader.ApplyFlags(instrument->PitchEnv, AMS2Instrument::vibEnvShift); + + // Scale envelopes to correct range + for(size_t i = 0; i < MAX_ENVPOINTS; i++) { - pIns->NoteMap[inotemap] = inotemap+1; - pIns->Keyboard[inotemap] = smpmap[pSmp->notemap[inotemap] & 0x0F]; + instrument->VolEnv.Values[i] = Util::Min(uint8(ENVELOPE_MAX), static_cast<uint8>((instrument->VolEnv.Values[i] * ENVELOPE_MAX + 64u) / 127u)); + instrument->PanEnv.Values[i] = Util::Min(uint8(ENVELOPE_MAX), static_cast<uint8>((instrument->PanEnv.Values[i] * ENVELOPE_MAX + 128u) / 255u)); + instrument->PitchEnv.Values[i] = Util::Min(uint8(ENVELOPE_MAX), static_cast<uint8>(32 + (static_cast<int8>(instrument->PitchEnv.Values[i] - 128) * vibAmp) / 255)); } - // Volume Envelope + + // Sample headers - we will have to read them even for shadow samples, and we will have to load them several times, + // as it is possible that shadow samples use different sample settings like base frequency or panning. + const SAMPLEINDEX firstSmp = GetNumSamples() + 1; + for(SAMPLEINDEX smp = 0; smp < numSamples; smp++) { - UINT pos = 0; - pIns->VolEnv.nNodes = (volenv->points > 16) ? 16 : volenv->points; - pIns->VolEnv.nSustainStart = pIns->VolEnv.nSustainEnd = volenv->sustain; - pIns->VolEnv.nLoopStart = volenv->loopbegin; - pIns->VolEnv.nLoopEnd = volenv->loopend; - for (UINT i=0; i<pIns->VolEnv.nNodes; i++) + if(firstSmp + smp >= MAX_SAMPLES) { - pIns->VolEnv.Values[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1); - pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8); - pIns->VolEnv.Ticks[i] = (WORD)pos; + file.Skip(sizeof(AMS2SampleHeader)); + break; } + ReadAMSString(m_szNames[firstSmp + smp], file); + + AMS2SampleHeader sampleHeader; + file.ReadConvertEndianness(sampleHeader); + sampleHeader.ConvertToMPT(Samples[firstSmp + smp]); + + uint16 settings = (instrHeader.shadowInstr & instrIndexMask) | ((smp << sampleIndexShift) & sampleIndexMask) | ((sampleHeader.flags & AMS2SampleHeader::smpPacked) ? packStatusMask : 0); + sampleSettings.push_back(settings); } - pIns->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3; - UINT envflags = lpStream[dwMemPos+3]; - if (envflags & 0x01) pIns->VolEnv.dwFlags |= ENV_LOOP; - if (envflags & 0x02) pIns->VolEnv.dwFlags |= ENV_SUSTAIN; - if (envflags & 0x04) pIns->VolEnv.dwFlags |= ENV_ENABLED; - dwMemPos += 5; - // Read Samples - for (UINT ismp=0; ismp<pSmp->samples; ismp++) + + firstSample.push_back(firstSmp); + m_nSamples = Util::Min(MAX_SAMPLES - 1, GetNumSamples() + numSamples); + } + + // Text + + // Read composer name + uint8 composerLength = file.ReadUint8(); + if(composerLength) + { + ReadMessage(file, composerLength, leAutodetect, ConvertAMSTextChars); + } + + // Channel names + for(CHANNELINDEX chn = 0; chn < 32; chn++) + { + ReadAMSString(ChnSettings[chn].szName, file); + } + + // RLE-Packed description text + AMS2Description descriptionHeader; + if(!file.ReadConvertEndianness(descriptionHeader)) + { + return true; + } + if(descriptionHeader.packedLen) + { + const size_t textLength = descriptionHeader.packedLen - sizeof(descriptionHeader); + vector<uint8> textIn, textOut(descriptionHeader.unpackedLen); + file.ReadVector(textIn, textLength); + + size_t readLen = 0, writeLen = 0; + while(readLen < textLength && writeLen < descriptionHeader.unpackedLen) { - ModSample *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Samples[smpmap[ismp]] : nullptr; - UINT smpnamelen = lpStream[dwMemPos]; - if ((psmp) && (smpnamelen) && (smpnamelen <= 22)) + uint8 c = textIn[readLen++]; + if(c == 0xFF && textLength - readLen >= 2) { - memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen); - StringFixer::SpaceToNullStringFixed(m_szNames[smpmap[ismp]], smpnamelen); - } - dwMemPos += smpnamelen + 1; - if (psmp) + c = textIn[readLen++]; + uint32 count = textIn[readLen++]; + for(size_t i = Util::Min(descriptionHeader.unpackedLen - writeLen, count); i != 0; i--) + { + textOut[writeLen++] = c; + } + } else { - AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos); - psmp->nGlobalVol = 64; - psmp->nPan = 128; - psmp->nLength = pams->length; - psmp->nLoopStart = pams->loopstart; - psmp->nLoopEnd = pams->loopend; - psmp->nC5Speed = pams->nC5Speed; - psmp->RelativeTone = pams->transpose; - psmp->nVolume = pams->volume / 2; - packedsamples[smpmap[ismp]] = pams->flags; - if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT; - if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP; - if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP; + textOut[writeLen++] = c; } - dwMemPos += sizeof(AMS2SAMPLE); } + // Packed text doesn't include any line breaks! + ReadFixedLineLengthMessage(&textOut[0], descriptionHeader.unpackedLen, 74, 0, ConvertAMSTextChars); } - if (dwMemPos + 256 >= dwMemLength) return true; - // Comments + + // Read Order List + vector<uint16> orders; + if(file.ReadVector(orders, fileHeader.numOrds)) { - UINT composernamelen = lpStream[dwMemPos]; - if (composernamelen) + Order.resize(fileHeader.numOrds); + for(size_t i = 0; i < fileHeader.numOrds; i++) { - ReadMessage(lpStream + dwMemPos + 1, composernamelen, leCR); + Order[i] = SwapBytesLE(orders[i]); } - dwMemPos += composernamelen + 1; - // channel names - for (UINT i=0; i<32; i++) - { - UINT chnnamlen = lpStream[dwMemPos]; - if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME)) - { - memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen); - StringFixer::SpaceToNullStringFixed(ChnSettings[i].szName, chnnamlen); - } - dwMemPos += chnnamlen + 1; - if (dwMemPos + chnnamlen + 256 >= dwMemLength) return true; - } - // packed comments (ignored) - UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos)); - dwMemPos += songtextlen; - if (dwMemPos + 256 >= dwMemLength) return true; } - // Order List + + // Read Patterns + for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++) { - if ((dwMemPos + 2 * psh->orders) >= dwMemLength) return true; - Order.resize(psh->orders, Order.GetInvalidPatIndex()); - for (UINT iOrd = 0; iOrd < psh->orders; iOrd++) + uint32 patLength = file.ReadUint32LE(); + FileReader patternChunk = file.GetChunk(patLength); + + const ROWINDEX numRows = patternChunk.ReadUint8() + 1; + // We don't need to know the number of channels or commands. + patternChunk.Skip(1); + + if(Patterns.Insert(pat, numRows)) { - Order[iOrd] = (PATTERNINDEX)*((WORD *)(lpStream + dwMemPos)); - dwMemPos += 2; + continue; } - } - // Pattern Data - for (UINT ipat=0; ipat<psh->patterns; ipat++) - { - if (dwMemPos+8 >= dwMemLength) return true; - UINT packedlen = *((LPDWORD)(lpStream+dwMemPos)); - UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]); - //UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F); - //UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5); - UINT patnamlen = lpStream[dwMemPos+6]; - dwMemPos += 4; - if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8)) + + char patternName[11]; + ReadAMSString(patternName, patternChunk); + Patterns[pat].SetName(patternName); + + enum { - if ((patnamlen) && (patnamlen < MAX_PATTERNNAME)) + emptyRow = 0xFF, // No commands on row + endOfRowMask = 0x80, // If set, no more commands on this row + noteMask = 0x40, // If set, no note+instr in this command + channelMask = 0x1F, // Mask for extracting channel + + // Note flags + readNextCmd = 0x80, // One more command follows + noteDataMask = 0x7F, // Extract note + + // Command flags + volCommand = 0x40, // Effect is compressed volume command + commandMask = 0x3F, // Command or volume mask + }; + + // Extended (non-Protracker) effects + static const uint8 effTrans[] = + { + CMD_S3MCMDEX, // Forward / Backward + CMD_PORTAMENTOUP, // Extra fine slide up + CMD_PORTAMENTODOWN, // Extra fine slide up + CMD_RETRIG, // Retrigger + CMD_NONE, + CMD_TONEPORTAVOL, // Toneporta with fine volume slide + CMD_VIBRATOVOL, // Vibrato with fine volume slide + CMD_NONE, + CMD_PANNINGSLIDE, + CMD_NONE, + CMD_VOLUMESLIDE, // Two times finder volume slide than Axx + CMD_NONE, + CMD_CHANNELVOLUME, // Channel volume (0...127) + CMD_PATTERNBREAK, // Long pattern break (in hex) + CMD_S3MCMDEX, // Fine slide commands + CMD_NONE, // Fractional BPM + CMD_KEYOFF, // Key off at tick xx + CMD_PORTAMENTOUP, // Porta up, but uses all octaves (?) + CMD_PORTAMENTODOWN, // Porta down, but uses all octaves (?) + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_GLOBALVOLSLIDE, // Global volume slide + CMD_NONE, + CMD_GLOBALVOLUME, // Global volume (0... 127) + }; + + for(ROWINDEX row = 0; row < numRows; row++) + { + PatternRow baseRow = Patterns[pat].GetRow(row); + while(patternChunk.BytesLeft()) { - char s[MAX_PATTERNNAME]; - memcpy(s, lpStream+dwMemPos+3, patnamlen); - StringFixer::SpaceToNullStringFixed(s, patnamlen); - SetPatternName(ipat, s); - } - if(Patterns.Insert(ipat, numrows)) return true; - // Unpack Pattern Data - LPCBYTE psrc = lpStream + dwMemPos; - UINT pos = 3 + patnamlen; - UINT row = 0; - while ((pos < packedlen) && (row < numrows)) - { - ModCommand *m = Patterns[ipat] + row * m_nChannels; - UINT byte1 = psrc[pos++]; - UINT ch = byte1 & 0x1F; - // Read Note + Instr - if (!(byte1 & 0x40)) + const uint8 flags = patternChunk.ReadUint8(); + if(flags == emptyRow) { - UINT byte2 = psrc[pos++]; - UINT note = byte2 & 0x7F; - if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF; - m[ch].instr = psrc[pos++]; - // Read Effect - while (byte2 & 0x80) + break; + } + + ModCommand &m = baseRow[flags & channelMask]; + bool moreCommands = true; + if(!(flags & noteMask)) + { + uint8 note = patternChunk.ReadUint8(), instr = patternChunk.ReadUint8(); + moreCommands = (note & readNextCmd) != 0; + note &= noteDataMask; + + if(note == 1) { - byte2 = psrc[pos++]; - if (byte2 & 0x40) + m.note = NOTE_KEYOFF; + } else if(note >= 2 && note <= 121) + { + m.note = note - 2 + NOTE_MIN; + } + m.instr = instr; + } + + while(moreCommands) + { + ModCommand origCmd = m; + const uint8 command = patternChunk.ReadUint8(), effect = (command & commandMask); + moreCommands = (command & readNextCmd) != 0; + + if(command & volCommand) + { + m.volcmd = VOLCMD_VOLUME; + m.vol = effect; + } else + { + m.param = patternChunk.ReadUint8(); + + if(effect < 0x10) { - m[ch].volcmd = VOLCMD_VOLUME; - m[ch].vol = byte2 & 0x3F; + m.command = effect; + ConvertModCommand(m); + + switch(m.command) + { + case CMD_PANNING8: + // 4-Bit panning + m.command = CMD_PANNING8; + m.param = (m.param & 0x0F) * 0x11; + break; + + case CMD_VOLUME: + m.command = CMD_NONE; + m.volcmd = VOLCMD_VOLUME; + m.vol = Util::Min((m.param + 1) / 2, 64); + break; + + case CMD_MODCMDEX: + if(m.param == 0x80) + { + // Break sample loop (cut after loop) + m.command = CMD_NONE; + } else + { + m.ExtendedMODtoS3MEffect(); + } + break; + } } else { - UINT command = byte2 & 0x3F; - UINT param = psrc[pos++]; - if (command == 0x0C) + if(effect - 0x10 < CountOf(effTrans)) { - m[ch].volcmd = VOLCMD_VOLUME; - m[ch].vol = param / 2; - } else - if (command < 0x10) + m.command = effTrans[effect - 0x10]; + + switch(effect) + { + case 0x10: + // Play sample forwards / backwards + if(m.param <= 0x01) + { + m.param |= 0x9E; + } else + { + m.command = CMD_NONE; + } + break; + + case 0x11: + case 0x12: + // Extra fine slides + m.param = Util::Min(uint8(0x0F), m.param) | 0xE0; + break; + + case 0x15: + case 0x16: + // Fine slides + m.param = (Util::Min(0x10, m.param + 1) / 2) | 0xF0; + break; + + case 0x1E: + // More fine slides + switch(m.param >> 4) + { + case 0x1: + // Fine porta up + m.command = CMD_PORTAMENTOUP; + m.param |= 0xF0; + break; + case 0x2: + // Fine porta down + m.command = CMD_PORTAMENTODOWN; + m.param |= 0xF0; + break; + case 0xA: + // Extra fine volume slide up + m.command = CMD_VOLUMESLIDE; + m.param = ((((m.param & 0x0F) + 1) / 2) << 4) | 0x0F; + break; + case 0xB: + // Extra fine volume slide down + m.command = CMD_VOLUMESLIDE; + m.param = (((m.param & 0x0F) + 1) / 2) | 0xF0; + break; + default: + m.command = CMD_NONE; + break; + } + break; + + case 0x1C: + // Adjust channel volume range + m.param = Util::Min((m.param + 1) / 2, 64); + break; + } + } + } + + if(origCmd.command == CMD_VOLUMESLIDE && (m.command == CMD_VIBRATO || m.command == CMD_TONEPORTAVOL) && m.param == 0) + { + // Merge commands + if(m.command == CMD_VIBRATO) { - m[ch].command = command; - m[ch].param = param; - ConvertModCommand(&m[ch]); + m.command = CMD_VIBRATOVOL; } else { - // TODO: AMS effects + m.command = CMD_TONEPORTAVOL; } + m.param = origCmd.param; + origCmd.command = CMD_NONE; } + + if(ModCommand::GetEffectWeight(origCmd.command) > ModCommand::GetEffectWeight(m.command)) + { + if(ModCommand::ConvertVolEffect(m.command, m.param, true)) + { + // Volume column to the rescue! + m.volcmd = m.command; + m.vol = m.param; + } + + m.command = origCmd.command; + m.param = origCmd.param; + } } } - if (byte1 & 0x80) row++; + + if(flags & endOfRowMask) + { + // End of row + break; + } } } - dwMemPos += packedlen; } + // Read Samples - for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Samples[iSmp].nLength) + for(SAMPLEINDEX smp = 0; smp < GetNumSamples(); smp++) { - if (dwMemPos >= dwMemLength - 9) return true; + if((sampleSettings[smp] & instrIndexMask) == 0) + { + // Only load samples that aren't part of a shadow instrument + SampleIO( + (Samples[smp + 1].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + (sampleSettings[smp] & packStatusMask) ? SampleIO::AMS : SampleIO::signedPCM) + .ReadSample(Samples[smp + 1], file); + } + } - dwMemPos += SampleIO( - (Samples[iSmp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, - SampleIO::mono, - SampleIO::littleEndian, - (packedsamples[iSmp] & 0x03) ? SampleIO::AMS, SampleIO::signedPCM) - .ReadSample(Samples[iSmp], format, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); + // Copy shadow samples + for(SAMPLEINDEX smp = 0; smp < GetNumSamples(); smp++) + { + INSTRUMENTINDEX sourceInstr = (sampleSettings[smp] & instrIndexMask); + if(sourceInstr == 0 + || --sourceInstr >= firstSample.size()) + { + continue; + } + + SAMPLEINDEX sourceSample = ((sampleSettings[smp] & sampleIndexMask) >> sampleIndexShift) + firstSample[sourceInstr]; + if(sourceSample > GetNumSamples()) + { + continue; + } + + // Copy over original sample + ModSample &sample = Samples[smp + 1]; + ModSample &source = Samples[sourceSample]; + if(source.uFlags & CHN_16BIT) + { + sample.uFlags |= CHN_16BIT; + } else + { + sample.uFlags &= ~CHN_16BIT; + } + sample.nLength = source.nLength; + if(sample.AllocateSample()) + { + memcpy(sample.pSample, source.pSample, source.GetSampleSizeInBytes()); + AdjustSampleLoop(sample); + } } + return true; -#endif } + ///////////////////////////////////////////////////////////////////// // AMS Sample unpacking Modified: trunk/OpenMPT/soundlib/Loaders.h =================================================================== --- trunk/OpenMPT/soundlib/Loaders.h 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/Loaders.h 2012-06-18 00:42:57 UTC (rev 1303) @@ -12,6 +12,7 @@ #include "Endianness.h" #include "../common/misc_util.h" #include "../common/StringFixer.h" +#include <vector> // Execute "action" if "request_bytes" bytes cannot be read from stream at position "position" // DEPRECATED. Use FileReader instead. @@ -177,8 +178,7 @@ T target; if(Read(target)) { - SwapBytesLE(target); - return target; + return SwapBytesLE(target); } else { return 0; @@ -194,8 +194,7 @@ T target; if(Read(target)) { - SwapBytesBE(target); - return target; + return SwapBytesBE(target); } else { return 0; @@ -383,7 +382,6 @@ template<typename T, size_t destSize> bool ReadArray(T (&destArray)[destSize]) { - static_assert(sizeof(destArray) == sizeof(T) * destSize, "Huh?"); if(CanRead(sizeof(destArray))) { memcpy(destArray, streamData + streamPos, sizeof(destArray)); @@ -396,20 +394,40 @@ } } + // Read destSize elements of type T into a vector. + // If successful, the file cursor is advanced by the size of the vector. + // Otherwise, the vector is cleared. + template<typename T> + bool ReadVector(std::vector<T> &destVector, size_t destSize) + { + const size_t readSize = sizeof(T) * destSize; + if(CanRead(readSize)) + { + destVector.resize(destSize); + memcpy(&destVector[0], streamData + streamPos, readSize); + streamPos += readSize; + return true; + } else + { + destVector.clear(); + return false; + } + } + // Compare a magic string with the current stream position. // Returns true if they are identical. // The file cursor is advanced by the the length of the "magic" string. bool ReadMagic(const char *magic) { const size_t magicLength = strlen(magic); - if(!CanRead(magicLength)) + if(CanRead(magicLength)) { - return false; - } else - { bool result = !memcmp(streamData + streamPos, magic, magicLength); streamPos += magicLength; return result; + } else + { + return false; } } Modified: trunk/OpenMPT/soundlib/Snd_defs.h =================================================================== --- trunk/OpenMPT/soundlib/Snd_defs.h 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/Snd_defs.h 2012-06-18 00:42:57 UTC (rev 1303) @@ -107,6 +107,7 @@ MOD_TYPE_J2B = 0x800000, MOD_TYPE_MPT = 0x1000000, MOD_TYPE_IMF = 0x2000000, + MOD_TYPE_AMS2 = 0x4000000, MOD_TYPE_UMX = 0x80000000, // Fake type }; @@ -145,7 +146,7 @@ #define CHN_KEYOFF 0x200 // exit sustain #define CHN_NOTEFADE 0x400 // fade note (instrument mode) #define CHN_SURROUND 0x800 // use surround channel -#define CHN_NOIDO 0x1000 // Indicates if the channel is near enough to an exact multiple of the base frequency that any interpolation won't be noticeable - or if interpolation was switched off completely. --Storlek +#define CHN_NOIDO 0x1000 // (IDO = Interpolation Do?) Indicates if the channel is near enough to an exact multiple of the base frequency that any interpolation won't be noticeable - or if interpolation was switched off completely. --Storlek #define CHN_HQSRC 0x2000 // High quality sample rate conversion (i.e. apply interpolation) #define CHN_FILTER 0x4000 // filtered output #define CHN_VOLUMERAMP 0x8000 // ramp volume @@ -307,7 +308,7 @@ #define SNDMIX_MUTECHNMODE 0x100000 // Notes are not played on muted channels -#define MAX_GLOBAL_VOLUME 256 +#define MAX_GLOBAL_VOLUME 256u // Resampling modes enum { Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-18 00:42:57 UTC (rev 1303) @@ -606,6 +606,7 @@ && !Read669(file) && !ReadFAR(file) && !ReadAMS(lpStream, dwMemLength) + && !ReadAMS2(file) && !ReadOKT(file) && !ReadPTM(lpStream, dwMemLength) && !ReadUlt(lpStream, dwMemLength) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-06-18 00:42:57 UTC (rev 1303) @@ -383,7 +383,7 @@ bool ReadDSM(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadFAR(FileReader &file); bool ReadAMS(const LPCBYTE lpStream, const DWORD dwMemLength); - bool ReadAMS2(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadAMS2(FileReader &file); bool ReadMDL(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadOKT(FileReader &file); bool ReadDMF(const LPCBYTE lpStream, const DWORD dwMemLength); Modified: trunk/OpenMPT/soundlib/Tables.cpp =================================================================== --- trunk/OpenMPT/soundlib/Tables.cpp 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/Tables.cpp 2012-06-18 00:42:57 UTC (rev 1303) @@ -41,6 +41,7 @@ { MOD_TYPE_WAV, "Wave", ".wav", 0 }, { MOD_TYPE_MID, "Midi", ".mid", 0 }, { MOD_TYPE_AMS, "Extreme's Tracker", ".ams", 0 }, + { MOD_TYPE_AMS2, "Velvet Studio", ".ams", 0 }, { MOD_TYPE_AMF|MOD_TYPE_AMF0,"Asylum / DSMI", ".amf", 0 }, { MOD_TYPE_DSM, "DSIK Format", ".dsm", 0 }, { MOD_TYPE_DMF, "X-Tracker", ".dmf", 0 }, Modified: trunk/OpenMPT/soundlib/modcommand.cpp =================================================================== --- trunk/OpenMPT/soundlib/modcommand.cpp 2012-06-17 15:31:45 UTC (rev 1302) +++ trunk/OpenMPT/soundlib/modcommand.cpp 2012-06-18 00:42:57 UTC (rev 1303) @@ -852,8 +852,8 @@ return false; case CMD_VIBRATO: if(force) - param = min(param, 9); - else if(param > 9) + param = min(param & 0x0F, 9); + else if((param & 0x0F) > 9) return false; effect = VOLCMD_VIBRATODEPTH; break; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-18 21:01:02
|
Revision: 1304 http://modplug.svn.sourceforge.net/modplug/?rev=1304&view=rev Author: saga-games Date: 2012-06-18 21:00:54 +0000 (Mon, 18 Jun 2012) Log Message: ----------- [Fix] Also rewrote AMSv1 loader - Patterns actually load correctly now. Modified Paths: -------------- trunk/OpenMPT/README trunk/OpenMPT/mptrack/Globals.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/soundlib/Load_ams.cpp trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/modcommand.cpp trunk/OpenMPT/soundlib/modcommand.h Modified: trunk/OpenMPT/README =================================================================== --- trunk/OpenMPT/README 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/README 2012-06-18 21:00:54 UTC (rev 1304) @@ -1,7 +1,7 @@ How to compile the code: -- Visual Studio 2003/2005/2008/2010 is required. Express versions won't work as - they don't include MFC. +- Visual Studio 2008/2010 is required. Express versions won't work as they don't + include MFC. - The VST 2.4 and ASIO SDKs are needed for compiling with VST and ASIO support. If you don't want this, uncomment #define NO_VST and #define NO_ASIO in the file StdAfx.h. Have a look at include/readme.txt to find out which exact files @@ -9,9 +9,8 @@ ASIO SDKs, get in touch with the main developers. - You need the DirectX SDK to enable DirectSound output. If you don't want this, uncomment #define NO_DSOUND in the file StdAfx.h. -- To compile the project, open mptrack/MPTRACK.SLN (if you're using VS2003 or - VS2005), mptrack/MPTRACK_08.SLN (VS2008) or mptrack/MPTRACK_10.SLN (VS2010) - and hit the compile button! :) +- To compile the project, open mptrack/MPTRACK_08.SLN (if you're using VS2008) + or mptrack/MPTRACK_10.SLN (VS2010) and hit the compile button! :) Modified: trunk/OpenMPT/mptrack/Globals.cpp =================================================================== --- trunk/OpenMPT/mptrack/Globals.cpp 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/mptrack/Globals.cpp 2012-06-18 21:00:54 UTC (rev 1304) @@ -19,7 +19,7 @@ #include "ctrl_smp.h" #include "ctrl_ins.h" #include "ctrl_com.h" -#include "ctrl_graph.h" //rewbs.graph +//#include "ctrl_graph.h" //rewbs.graph #include "globals.h" #ifdef _DEBUG @@ -361,7 +361,7 @@ { //rewbs.graph case IDD_CONTROL_GRAPH: - pDlg = new CCtrlGraph(); + //pDlg = new CCtrlGraph(); break; //end rewbs.graph case IDD_CONTROL_COMMENTS: Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-06-18 21:00:54 UTC (rev 1304) @@ -378,7 +378,6 @@ m_SndFile.ChangeModTypeTo(MOD_TYPE_MOD); break; case MOD_TYPE_MED: - case MOD_TYPE_AMS: m_SndFile.ChangeModTypeTo(MOD_TYPE_XM); if ((m_SndFile.m_nDefaultTempo == 125) && (m_SndFile.m_nDefaultSpeed == 6) && (!m_SndFile.m_nInstruments)) { Modified: trunk/OpenMPT/soundlib/Load_ams.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/soundlib/Load_ams.cpp 2012-06-18 21:00:54 UTC (rev 1304) @@ -6,10 +6,9 @@ * and thus they also renamed their tracker from * "Extreme's Tracker" to "Velvet Studio". * While the two programs look rather similiar, the structure of both - * programs' "AMS" format is significantly different - Velvet Studio is a - * rather advanced tracker in comparison to Extreme's Tracker. - * Authors: Olivier Lapicque - * OpenMPT Devs + * programs' "AMS" format is significantly different in some places - + * Velvet Studio is a rather advanced tracker in comparison to Extreme's Tracker. + * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ @@ -17,278 +16,472 @@ #include "stdafx.h" #include "Loaders.h" -#pragma warning(disable:4244) //"conversion from 'type1' to 'type2', possible loss of data" -#pragma pack(push, 1) +///////////////////////////////////////////////////////////////////// +// Common code for both AMS formats -typedef struct AMSFILEHEADER -{ - char szHeader[7]; // "Extreme" - BYTE verlo, verhi; // 0x??,0x01 - BYTE chncfg; - BYTE samples; - WORD patterns; - WORD orders; - BYTE vmidi; - WORD extra; -} AMSFILEHEADER; - -typedef struct AMSSAMPLEHEADER -{ - DWORD length; - DWORD loopstart; - DWORD loopend; - BYTE finetune_and_pan; - WORD samplerate; // C-2 = 8363 - BYTE volume; // 0-127 - BYTE infobyte; -} AMSSAMPLEHEADER; - - -#pragma pack(pop) - - // Callback function for reading text void ConvertAMSTextChars(char &c) //------------------------------- { switch((unsigned char)c) { - case 0x00: - case 0x81: c = ' '; break; + case 0x00: c = ' '; break; case 0x14: c = '\xF6'; break; case 0x19: c = '\xD6'; break; case 0x04: c = '\xE4'; break; case 0x0E: c = '\xC4'; break; case 0x06: c = '\xE5'; break; case 0x0F: c = '\xC5'; break; - default: - if((unsigned char)c > 0x81) - c = '\r'; - break; } } -bool CSoundFile::ReadAMS(const LPCBYTE lpStream, const DWORD dwMemLength) -//----------------------------------------------------------------------- +// Read variable-length AMS string (we ignore the maximum text length specified by the AMS specs and accept any length). +template<size_t destSize> +bool ReadAMSString(char (&destBuffer)[destSize], FileReader &file) +//---------------------------------------------------------------- { - BYTE pkinf[MAX_SAMPLES]; - AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream; - DWORD dwMemPos; - UINT tmp, tmp2; + const size_t length = file.ReadUint8(); + return file.ReadString<StringFixer::spacePadded>(destBuffer, length); +} - if ((!lpStream) || (dwMemLength < 126)) return false; - if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7)) - || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples >= MAX_SAMPLES) - || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS)) - { - return false; - } - dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra; - if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) >= dwMemLength) return false; - m_nType = MOD_TYPE_AMS; - m_nInstruments = 0; - m_nChannels = (pfh->chncfg & 0x1F) + 1; - m_nSamples = pfh->samples; - for (UINT nSmp=1; nSmp <= m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER)) - { - AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos); - ModSample *pSmp = &Samples[nSmp]; - pSmp->nLength = psh->length; - pSmp->nLoopStart = psh->loopstart; - pSmp->nLoopEnd = psh->loopend; - pSmp->nGlobalVol = 64; - pSmp->nVolume = psh->volume << 1; - pSmp->nC5Speed = psh->samplerate; - pSmp->nPan = (psh->finetune_and_pan & 0xF0); - if (pSmp->nPan < 0x80) pSmp->nPan += 0x10; - pSmp->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F); - pSmp->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0; - if ((pSmp->nLoopEnd <= pSmp->nLength) && (pSmp->nLoopStart+4 <= pSmp->nLoopEnd)) pSmp->uFlags |= CHN_LOOP; - pkinf[nSmp] = psh->infobyte; - } - // Read Song Name - if (dwMemPos + 1 >= dwMemLength) return true; - tmp = lpStream[dwMemPos++]; - if (dwMemPos + tmp >= dwMemLength) return true; - if(tmp) +// Read AMS or AMS2 (newVersion = true) pattern. At least this part of the format is more or less identical between the two trackers... +void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patternChunk, CSoundFile &sndFile) +//---------------------------------------------------------------------------------------------------- +{ + enum { - StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); - dwMemPos += tmp; - } + emptyRow = 0xFF, // No commands on row + endOfRowMask = 0x80, // If set, no more commands on this row + noteMask = 0x40, // If set, no note+instr in this command + channelMask = 0x1F, // Mask for extracting channel + // Note flags + readNextCmd = 0x80, // One more command follows + noteDataMask = 0x7F, // Extract note - // Read sample names - for (UINT sNam=1; sNam<=m_nSamples; sNam++) - { - if (dwMemPos + 1 >= dwMemLength) return true; - tmp = lpStream[dwMemPos++]; - if (dwMemPos + tmp >= dwMemLength) return true; - if(tmp) - { - StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[sNam], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); - dwMemPos += tmp; - } - } + // Command flags + volCommand = 0x40, // Effect is compressed volume command + commandMask = 0x3F, // Command or volume mask + }; - // Read Channel names - for (UINT cNam=0; cNam<m_nChannels; cNam++) + // Effect translation table for extended (non-Protracker) effects + static const ModCommand::COMMAND effTrans[] = { - if (dwMemPos + 1 >= dwMemLength) return true; - uint8 chnnamlen = lpStream[dwMemPos++]; - if (dwMemPos + tmp >= dwMemLength) return true; - if(chnnamlen) - { - StringFixer::ReadString<StringFixer::maybeNullTerminated>(ChnSettings[cNam].szName, reinterpret_cast<const char *>(lpStream + dwMemPos), chnnamlen); - dwMemPos += chnnamlen; - } - } + CMD_S3MCMDEX, // Forward / Backward + CMD_PORTAMENTOUP, // Extra fine slide up + CMD_PORTAMENTODOWN, // Extra fine slide up + CMD_RETRIG, // Retrigger + CMD_NONE, + CMD_TONEPORTAVOL, // Toneporta with fine volume slide + CMD_VIBRATOVOL, // Vibrato with fine volume slide + CMD_NONE, + CMD_PANNINGSLIDE, + CMD_NONE, + CMD_VOLUMESLIDE, // Two times finder volume slide than Axx + CMD_NONE, + CMD_CHANNELVOLUME, // Channel volume (0...127) + CMD_PATTERNBREAK, // Long pattern break (in hex) + CMD_S3MCMDEX, // Fine slide commands + CMD_NONE, // Fractional BPM + CMD_KEYOFF, // Key off at tick xx + CMD_PORTAMENTOUP, // Porta up, but uses all octaves (?) + CMD_PORTAMENTODOWN, // Porta down, but uses all octaves (?) + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_NONE, + CMD_GLOBALVOLSLIDE, // Global volume slide + CMD_NONE, + CMD_GLOBALVOLUME, // Global volume (0... 127) + }; - // Read Pattern Names - for (UINT pNam = 0; pNam < pfh->patterns; pNam++) - { - if (dwMemPos + 1 >= dwMemLength) return true; - tmp = lpStream[dwMemPos++]; - tmp2 = min(tmp, MAX_PATTERNNAME - 1); // not counting null char - if (dwMemPos + tmp >= dwMemLength) return true; - Patterns.Insert(pNam, 64); // Create pattern now, so that the name won't be overwritten later. - if(tmp2) - { - Patterns[pNam].SetName((char *)(lpStream + dwMemPos), tmp2 + 1); - } - dwMemPos += tmp; - } + static ModCommand dummy; - // Read Song Comments - tmp = *((WORD *)(lpStream+dwMemPos)); - dwMemPos += 2; - if (dwMemPos + tmp >= dwMemLength) return true; - if (tmp) + for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { - ReadMessage(lpStream + dwMemPos, tmp, leCR, &ConvertAMSTextChars); - } - dwMemPos += tmp; - - // Read Order List - Order.resize(pfh->orders, Order.GetInvalidPatIndex()); - for (UINT iOrd=0; iOrd < pfh->orders; iOrd++, dwMemPos += 2) - { - Order[iOrd] = (PATTERNINDEX)*((WORD *)(lpStream + dwMemPos)); - } - - // Read Patterns - for (UINT iPat=0; iPat<pfh->patterns; iPat++) - { - if (dwMemPos + 4 >= dwMemLength) return true; - UINT len = *((DWORD *)(lpStream + dwMemPos)); - dwMemPos += 4; - if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return true; - // Pattern has been inserted when reading pattern names - ModCommand* m = Patterns[iPat]; - if (!m) return true; - const BYTE *p = lpStream + dwMemPos; - UINT row = 0, i = 0; - while ((row < Patterns[iPat].GetNumRows()) && (i+2 < len)) + PatternRow baseRow = pattern.GetRow(row); + while(patternChunk.BytesLeft()) { - BYTE b0 = p[i++]; - BYTE b1 = p[i++]; - BYTE b2 = 0; - UINT ch = b0 & 0x3F; - // Note+Instr - if (!(b0 & 0x40)) + const uint8 flags = patternChunk.ReadUint8(); + if(flags == emptyRow) { - b2 = p[i++]; - if (ch < m_nChannels) + break; + } + + const CHANNELINDEX chn = (flags & channelMask); + ModCommand &m = chn < pattern.GetNumChannels() ? baseRow[chn] : dummy; + bool moreCommands = true; + if(!(flags & noteMask)) + { + // Read note + instr + uint8 note = patternChunk.ReadUint8(); + moreCommands = (note & readNextCmd) != 0; + note &= noteDataMask; + + if(note == 1) { - if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25; - m[ch].instr = b2; - } - if (b1 & 0x80) + m.note = NOTE_KEYOFF; + } else if(note >= 2 && note <= 121 && newVersion) { - b0 |= 0x40; - b1 = p[i++]; + m.note = note - 2 + NOTE_MIN; + } else if(note >= 12 && note <= 108 && !newVersion) + { + m.note = note + 12 + NOTE_MIN; } + m.instr = patternChunk.ReadUint8(); } - // Effect - if (b0 & 0x40) + + while(moreCommands) { - anothercommand: - if (b1 & 0x40) + // Read one more effect command + ModCommand origCmd = m; + const uint8 command = patternChunk.ReadUint8(), effect = (command & commandMask); + moreCommands = (command & readNextCmd) != 0; + + if(command & volCommand) { - if (ch < m_nChannels) - { - m[ch].volcmd = VOLCMD_VOLUME; - m[ch].vol = b1 & 0x3F; - } + m.volcmd = VOLCMD_VOLUME; + m.vol = effect; } else { - b2 = p[i++]; - if (ch < m_nChannels) + m.param = patternChunk.ReadUint8(); + + if(effect < 0x10) { - UINT cmd = b1 & 0x3F; - if (cmd == 0x0C) + // PT commands + m.command = effect; + sndFile.ConvertModCommand(m); + + // Post-fix some commands + switch(m.command) { - m[ch].volcmd = VOLCMD_VOLUME; - m[ch].vol = b2 >> 1; - } else - if (cmd == 0x0E) + case CMD_PANNING8: + // 4-Bit panning + m.command = CMD_PANNING8; + m.param = (m.param & 0x0F) * 0x11; + break; + + case CMD_VOLUME: + m.command = CMD_NONE; + m.volcmd = VOLCMD_VOLUME; + m.vol = static_cast<ModCommand::VOL>(Util::Min((m.param + 1) / 2, 64)); + break; + + case CMD_MODCMDEX: + if(m.param == 0x80) + { + // Break sample loop (cut after loop) + m.command = CMD_NONE; + } else + { + m.ExtendedMODtoS3MEffect(); + } + break; + } + } else if(effect - 0x10 < CountOf(effTrans)) + { + // Extended commands + m.command = effTrans[effect - 0x10]; + + // Post-fix some commands + switch(effect) { - if (!m[ch].command) + case 0x10: + // Play sample forwards / backwards + if(m.param <= 0x01) { - UINT command = CMD_S3MCMDEX; - UINT param = b2; - switch(param & 0xF0) - { - case 0x00: if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break; - 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 & 0x0F) | 0x30; break; - case 0x50: param = (param & 0x0F) | 0x20; break; - case 0x60: param = (param & 0x0F) | 0xB0; break; - case 0x70: param = (param & 0x0F) | 0x40; break; - case 0x90: command = CMD_RETRIG; param &= 0x0F; break; - case 0xA0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break; - case 0xB0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break; - } - m[ch].command = command; - m[ch].param = param; + m.param |= 0x9E; + } else + { + m.command = CMD_NONE; } - } else + break; + + case 0x11: + case 0x12: + // Extra fine slides + m.param = static_cast<ModCommand::PARAM>(Util::Min(uint8(0x0F), m.param) | 0xE0); + break; + + case 0x15: + case 0x16: + // Fine slides + m.param = static_cast<ModCommand::PARAM>((Util::Min(0x10, m.param + 1) / 2) | 0xF0); + break; + + case 0x1E: + // More fine slides + switch(m.param >> 4) + { + case 0x1: + // Fine porta up + m.command = CMD_PORTAMENTOUP; + m.param |= 0xF0; + break; + case 0x2: + // Fine porta down + m.command = CMD_PORTAMENTODOWN; + m.param |= 0xF0; + break; + case 0xA: + // Extra fine volume slide up + m.command = CMD_VOLUMESLIDE; + m.param = ((((m.param & 0x0F) + 1) / 2) << 4) | 0x0F; + break; + case 0xB: + // Extra fine volume slide down + m.command = CMD_VOLUMESLIDE; + m.param = (((m.param & 0x0F) + 1) / 2) | 0xF0; + break; + default: + m.command = CMD_NONE; + break; + } + break; + + case 0x1C: + // Adjust channel volume range + m.param = static_cast<ModCommand::PARAM>(Util::Min((m.param + 1) / 2, 64)); + break; + } + } + + // Try merging commands first + ModCommand::CombineEffects(m.command, m.param, origCmd.command, origCmd.param); + + if(ModCommand::GetEffectWeight(origCmd.command) > ModCommand::GetEffectWeight(m.command)) + { + if(m.volcmd == VOLCMD_NONE && ModCommand::ConvertVolEffect(m.command, m.param, true)) { - m[ch].command = cmd; - m[ch].param = b2; - ConvertModCommand(m[ch]); + // Volume column to the rescue! + m.volcmd = m.command; + m.vol = m.param; } + + m.command = origCmd.command; + m.param = origCmd.param; } } - if (b1 & 0x80) - { - b1 = p[i++]; - if (i <= len) goto anothercommand; - } } - if (b0 & 0x80) + + if(flags & endOfRowMask) { - row++; - m += m_nChannels; + // End of row + break; } } - dwMemPos += len; } +} + +///////////////////////////////////////////////////////////////////// +// AMS (Extreme's Tracker) 1.x loader + +#pragma pack(push, 1) + +// AMS File Header +struct AMSFileHeader +{ + uint8 versionLow; + uint8 versionHigh; + uint8 channelConfig; + uint8 numSamps; + uint16 numPats; + uint16 numOrds; + uint8 midiChannels; + uint16 extraSize; + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(numPats); + SwapBytesLE(numOrds); + SwapBytesLE(extraSize); + } +}; + + +// AMS Sample Header +struct AMSSampleHeader +{ + enum SampleFlags + { + smp16Bit = 0x80, + smpPacked = 0x03, + }; + + uint32 length; + uint32 loopStart; + uint32 loopEnd; + uint8 panFinetune; // High nibble = pan position, low nibble = finetune value + uint16 sampleRate; + uint8 volume; // 0...127 + uint8 flags; // See SampleFlags + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(sampleRate); + } + + // Convert sample header to OpenMPT's internal format. + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + + mptSmp.nLength = length; + mptSmp.nLoopStart = Util::Min(loopStart, length); + mptSmp.nLoopEnd = Util::Min(loopEnd, length); + + mptSmp.nVolume = (Util::Min(uint8(127), volume) * 256 + 64) / 127; + if(panFinetune & 0xF0) + { + mptSmp.nPan = (panFinetune & 0xF0); + mptSmp.uFlags = CHN_PANNING; + } + + mptSmp.nC5Speed = 2 * sampleRate; + if(sampleRate == 0) + { + mptSmp.nC5Speed = 2 * 8363; + } + + uint32 newC4speed = ModSample::TransposeToFrequency(0, MOD2XMFineTune(panFinetune & 0x0F)); + mptSmp.nC5Speed = (mptSmp.nC5Speed * newC4speed) / 8363; + + if(mptSmp.nLoopStart < mptSmp.nLoopEnd) + { + mptSmp.uFlags |= CHN_LOOP; + } + } +}; + + +#pragma pack(pop) + + +bool CSoundFile::ReadAMS(FileReader &file) +//---------------------------------------- +{ + file.Rewind(); + + AMSFileHeader fileHeader; + if(!file.ReadMagic("Extreme") + || !file.ReadConvertEndianness(fileHeader) + || !file.Skip(fileHeader.extraSize) + || file.BytesLeft() < fileHeader.numSamps * sizeof(AMSSampleHeader) + || fileHeader.versionHigh != 0x01) + { + return false; + } + + m_nType = MOD_TYPE_AMS; + m_dwSongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; + m_nInstruments = 0; + m_nChannels = (fileHeader.channelConfig & 0x1F) + 1; + m_nSamples = fileHeader.numSamps; + SetModFlag(MSF_COMPATIBLE_PLAY, true); + SetupMODPanning(true); + + vector<bool> packSample(fileHeader.numSamps); + + STATIC_ASSERT(MAX_SAMPLES > 255); + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + { + AMSSampleHeader sampleHeader; + file.ReadConvertEndianness(sampleHeader); + sampleHeader.ConvertToMPT(Samples[smp]); + packSample[smp - 1] = (sampleHeader.flags & AMSSampleHeader::smpPacked) != 0; + } + + // Texts + ReadAMSString(m_szNames[0], file); + + // Read sample names + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + { + ReadAMSString(m_szNames[smp], file); + } + + // Read channel names + for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) + { + ReadAMSString(ChnSettings[chn].szName, file); + } + + // Read pattern names + for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++) + { + char name[11]; + ReadAMSString(name, file); + // Create pattern now, so name won't be reset later. + if(!Patterns.Insert(pat, 64)) + { + Patterns[pat].SetName(name); + } + } + + // Read packed song message + const uint16 packedLength = file.ReadUint16LE(); + if(packedLength) + { + vector<uint8> textIn, textOut; + file.ReadVector(textIn, packedLength); + textOut.reserve(packedLength); + + for(vector<uint8>::iterator c = textIn.begin(); c != textIn.end(); c++) + { + if(*c & 0x80) + { + textOut.insert(textOut.end(), (*c & 0x7F), ' '); + } else + { + textOut.push_back(*c); + } + } + + // Packed text doesn't include any line breaks! + ReadFixedLineLengthMessage(&textOut[0], textOut.size(), 76, 0, ConvertAMSTextChars); + } + + // Read Order List + vector<uint16> orders; + if(file.ReadVector(orders, fileHeader.numOrds)) + { + Order.resize(fileHeader.numOrds); + for(size_t i = 0; i < fileHeader.numOrds; i++) + { + Order[i] = SwapBytesLE(orders[i]); + } + } + + // Read patterns + for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++) + { + uint32 patLength = file.ReadUint32LE(); + FileReader patternChunk = file.GetChunk(patLength); + + ReadAMSPattern(Patterns[pat], false, patternChunk, *this); + } + // Read Samples - for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Samples[iSmp].nLength) + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { - if (dwMemPos >= dwMemLength - 9) return true; - dwMemPos += SampleIO( - (Samples[iSmp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO( + (Samples[smp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, - SampleIO::AMS) - .ReadSample(Samples[iSmp], (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); + packSample[smp - 1] ? SampleIO::AMS : SampleIO::signedPCM) + .ReadSample(Samples[smp], file); } return true; } @@ -360,7 +553,7 @@ { if(i != 0) { - mptEnv.Ticks[i] = mptEnv.Ticks[i - 1] + Util::Max(1, env.data[i][0] | ((env.data[i][1] & 0x01) << 8)); + mptEnv.Ticks[i] = mptEnv.Ticks[i - 1] + static_cast<uint16>(Util::Max(1, env.data[i][0] | ((env.data[i][1] & 0x01) << 8))); } mptEnv.Values[i] = env.data[i][2]; } @@ -400,7 +593,7 @@ void ApplyFlags(InstrumentEnvelope &mptEnv, EnvelopeFlags shift) const { - const uint8 flags = envFlags >> (shift * 3); + const int flags = envFlags >> (shift * 3); if(flags & envEnabled) mptEnv.dwFlags |= ENV_ENABLED; if(flags & envLoop) mptEnv.dwFlags |= ENV_LOOP; if(flags & envSustain) mptEnv.dwFlags |= ENV_SUSTAIN; @@ -459,7 +652,7 @@ mptSmp.nLoopEnd = Util::Min(loopEnd, length); mptSmp.nC5Speed = c4speed * 2; - if(!mptSmp.nC5Speed) + if(c4speed == 0) { mptSmp.nC5Speed = 8363 * 2; } @@ -511,16 +704,6 @@ #pragma pack() -// Read variable-length AMS string (we ignore the maximum text length specified by the AMS specs and accept any length). -template<size_t destSize> -bool ReadAMSString(char (&destBuffer)[destSize], FileReader &file) -//---------------------------------------------------------------- -{ - const size_t length = file.ReadUint8(); - return file.ReadString<StringFixer::spacePadded>(destBuffer, length); -} - - bool CSoundFile::ReadAMS2(FileReader &file) //----------------------------------------- { @@ -557,6 +740,8 @@ m_nSamplePreAmp = m_nVSTiVolume = 48; m_nInstruments = fileHeader.numIns; m_nChannels = 32; + SetModFlag(MSF_COMPATIBLE_PLAY, true); + SetupMODPanning(true); // Instruments vector<SAMPLEINDEX> firstSample; // First sample of instrument @@ -569,6 +754,7 @@ packStatusMask = 0x8000, // If bit is set, sample is packed }; + STATIC_ASSERT(MAX_INSTRUMENTS > 255); for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { ModInstrument *instrument = AllocateInstrument(ins); @@ -636,7 +822,7 @@ } firstSample.push_back(firstSmp); - m_nSamples = Util::Min(MAX_SAMPLES - 1, GetNumSamples() + numSamples); + m_nSamples = static_cast<SAMPLEINDEX>(Util::Min(MAX_SAMPLES - 1, GetNumSamples() + numSamples)); } // Text @@ -717,234 +903,7 @@ ReadAMSString(patternName, patternChunk); Patterns[pat].SetName(patternName); - enum - { - emptyRow = 0xFF, // No commands on row - endOfRowMask = 0x80, // If set, no more commands on this row - noteMask = 0x40, // If set, no note+instr in this command - channelMask = 0x1F, // Mask for extracting channel - - // Note flags - readNextCmd = 0x80, // One more command follows - noteDataMask = 0x7F, // Extract note - - // Command flags - volCommand = 0x40, // Effect is compressed volume command - commandMask = 0x3F, // Command or volume mask - }; - - // Extended (non-Protracker) effects - static const uint8 effTrans[] = - { - CMD_S3MCMDEX, // Forward / Backward - CMD_PORTAMENTOUP, // Extra fine slide up - CMD_PORTAMENTODOWN, // Extra fine slide up - CMD_RETRIG, // Retrigger - CMD_NONE, - CMD_TONEPORTAVOL, // Toneporta with fine volume slide - CMD_VIBRATOVOL, // Vibrato with fine volume slide - CMD_NONE, - CMD_PANNINGSLIDE, - CMD_NONE, - CMD_VOLUMESLIDE, // Two times finder volume slide than Axx - CMD_NONE, - CMD_CHANNELVOLUME, // Channel volume (0...127) - CMD_PATTERNBREAK, // Long pattern break (in hex) - CMD_S3MCMDEX, // Fine slide commands - CMD_NONE, // Fractional BPM - CMD_KEYOFF, // Key off at tick xx - CMD_PORTAMENTOUP, // Porta up, but uses all octaves (?) - CMD_PORTAMENTODOWN, // Porta down, but uses all octaves (?) - CMD_NONE, - CMD_NONE, - CMD_NONE, - CMD_NONE, - CMD_NONE, - CMD_NONE, - CMD_NONE, - CMD_GLOBALVOLSLIDE, // Global volume slide - CMD_NONE, - CMD_GLOBALVOLUME, // Global volume (0... 127) - }; - - for(ROWINDEX row = 0; row < numRows; row++) - { - PatternRow baseRow = Patterns[pat].GetRow(row); - while(patternChunk.BytesLeft()) - { - const uint8 flags = patternChunk.ReadUint8(); - if(flags == emptyRow) - { - break; - } - - ModCommand &m = baseRow[flags & channelMask]; - bool moreCommands = true; - if(!(flags & noteMask)) - { - uint8 note = patternChunk.ReadUint8(), instr = patternChunk.ReadUint8(); - moreCommands = (note & readNextCmd) != 0; - note &= noteDataMask; - - if(note == 1) - { - m.note = NOTE_KEYOFF; - } else if(note >= 2 && note <= 121) - { - m.note = note - 2 + NOTE_MIN; - } - m.instr = instr; - } - - while(moreCommands) - { - ModCommand origCmd = m; - const uint8 command = patternChunk.ReadUint8(), effect = (command & commandMask); - moreCommands = (command & readNextCmd) != 0; - - if(command & volCommand) - { - m.volcmd = VOLCMD_VOLUME; - m.vol = effect; - } else - { - m.param = patternChunk.ReadUint8(); - - if(effect < 0x10) - { - m.command = effect; - ConvertModCommand(m); - - switch(m.command) - { - case CMD_PANNING8: - // 4-Bit panning - m.command = CMD_PANNING8; - m.param = (m.param & 0x0F) * 0x11; - break; - - case CMD_VOLUME: - m.command = CMD_NONE; - m.volcmd = VOLCMD_VOLUME; - m.vol = Util::Min((m.param + 1) / 2, 64); - break; - - case CMD_MODCMDEX: - if(m.param == 0x80) - { - // Break sample loop (cut after loop) - m.command = CMD_NONE; - } else - { - m.ExtendedMODtoS3MEffect(); - } - break; - } - } else - { - if(effect - 0x10 < CountOf(effTrans)) - { - m.command = effTrans[effect - 0x10]; - - switch(effect) - { - case 0x10: - // Play sample forwards / backwards - if(m.param <= 0x01) - { - m.param |= 0x9E; - } else - { - m.command = CMD_NONE; - } - break; - - case 0x11: - case 0x12: - // Extra fine slides - m.param = Util::Min(uint8(0x0F), m.param) | 0xE0; - break; - - case 0x15: - case 0x16: - // Fine slides - m.param = (Util::Min(0x10, m.param + 1) / 2) | 0xF0; - break; - - case 0x1E: - // More fine slides - switch(m.param >> 4) - { - case 0x1: - // Fine porta up - m.command = CMD_PORTAMENTOUP; - m.param |= 0xF0; - break; - case 0x2: - // Fine porta down - m.command = CMD_PORTAMENTODOWN; - m.param |= 0xF0; - break; - case 0xA: - // Extra fine volume slide up - m.command = CMD_VOLUMESLIDE; - m.param = ((((m.param & 0x0F) + 1) / 2) << 4) | 0x0F; - break; - case 0xB: - // Extra fine volume slide down - m.command = CMD_VOLUMESLIDE; - m.param = (((m.param & 0x0F) + 1) / 2) | 0xF0; - break; - default: - m.command = CMD_NONE; - break; - } - break; - - case 0x1C: - // Adjust channel volume range - m.param = Util::Min((m.param + 1) / 2, 64); - break; - } - } - } - - if(origCmd.command == CMD_VOLUMESLIDE && (m.command == CMD_VIBRATO || m.command == CMD_TONEPORTAVOL) && m.param == 0) - { - // Merge commands - if(m.command == CMD_VIBRATO) - { - m.command = CMD_VIBRATOVOL; - } else - { - m.command = CMD_TONEPORTAVOL; - } - m.param = origCmd.param; - origCmd.command = CMD_NONE; - } - - if(ModCommand::GetEffectWeight(origCmd.command) > ModCommand::GetEffectWeight(m.command)) - { - if(ModCommand::ConvertVolEffect(m.command, m.param, true)) - { - // Volume column to the rescue! - m.volcmd = m.command; - m.vol = m.param; - } - - m.command = origCmd.command; - m.param = origCmd.param; - } - } - } - - if(flags & endOfRowMask) - { - // End of row - break; - } - } - } + ReadAMSPattern(Patterns[pat], true, patternChunk, *this); } // Read Samples @@ -1004,69 +963,90 @@ ///////////////////////////////////////////////////////////////////// // AMS Sample unpacking -void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter) -//----------------------------------------------------------------------------------------- +void AMSUnpack(const char * const source, size_t sourceSize, char * const dest, const size_t destSize, char packCharacter) +//------------------------------------------------------------------------------------------------------------------------ { - UINT tmplen = dmax; - signed char *amstmp = new signed char[tmplen]; + int8 *tempBuf = new (std::nothrow) int8[destSize]; + if(tempBuf == nullptr) + { + return; + } - if (!amstmp) return; // Unpack Loop { - signed char *p = amstmp; - UINT i=0, j=0; - while ((i < inputlen) && (j < tmplen)) + const int8 *in = source; + int8 *out = tempBuf; + + size_t i = sourceSize, j = destSize; + while(i != 0 && j != 0) { - signed char ch = psrc[i++]; - if (ch == packcharacter) + int8 ch = *(in++); + if(--i != 0 && ch == packCharacter) { - BYTE ch2 = psrc[i++]; - if (ch2) + uint8 repCount = *(in++); + repCount = static_cast<uint8>(Util::Min(static_cast<size_t>(repCount), j)); + if(--i != 0 && repCount) { - ch = psrc[i++]; - while (ch2--) + ch = *(in++); + i--; + while(repCount-- != 0) { - p[j++] = ch; - if (j >= tmplen) break; + *(out++) = ch; + j--; } - } else p[j++] = packcharacter; - } else p[j++] = ch; + } else + { + *(out++) = packCharacter; + j--; + } + } else + { + *(out++) = ch; + j--; + } } } + // Bit Unpack Loop { - signed char *p = amstmp; - UINT bitcount = 0x80, dh; - UINT k=0; - for (UINT i=0; i<dmax; i++) + int8 *out = tempBuf; + uint16 bitcount = 0x80; + size_t k = 0; + for(size_t i = 0; i < destSize; i++) { - BYTE al = *p++; - dh = 0; - for (UINT count=0; count<8; count++) + uint8 al = *out++; + uint16 dh = 0; + for(uint16 count = 0; count < 8; count++) { - UINT bl = al & bitcount; - bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF; - bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF; - pdest[k++] |= bl; - if (k >= dmax) + uint16 bl = al & bitcount; + bl = ((bl | (bl << 8)) >> ((dh + 8 - count) & 7)) & 0xFF; + bitcount = ((bitcount | (bitcount << 8)) >> 1) & 0xFF; + dest[k++] |= bl; + if(k >= destSize) { k = 0; dh++; } } - bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF; + bitcount = ((bitcount | (bitcount << 8)) >> dh) & 0xFF; } } + // Delta Unpack { - signed char old = 0; - for (UINT i=0; i<dmax; i++) + int8 old = 0; + int8 *out = dest; + for(size_t i = destSize; i != 0; i--) { - int pos = ((LPBYTE)pdest)[i]; - if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F); - old -= (signed char)pos; - pdest[i] = old; + int pos = *reinterpret_cast<uint8 *>(out); + if(pos != 128 && (pos & 0x80) != 0) + { + pos = -(pos & 0x7F); + } + old -= static_cast<int8>(pos); + *(out++) = old; } } - delete[] amstmp; + + delete[] tempBuf; } Modified: trunk/OpenMPT/soundlib/SampleIO.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleIO.cpp 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/soundlib/SampleIO.cpp 2012-06-18 21:00:54 UTC (rev 1304) @@ -17,7 +17,7 @@ // External decompressors -extern void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter); +extern void AMSUnpack(const char * const source, size_t sourceSize, char * const dest, const size_t destSize, char packCharacter); extern uint16 MDLReadBits(uint32 &bitbuf, uint32 &bitnum, const uint8 *(&ibuf), int8 n); extern int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, UINT maxlen); extern void ITUnpack8Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215); Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-18 21:00:54 UTC (rev 1304) @@ -605,7 +605,7 @@ && !ReadDBM(lpStream, dwMemLength) && !Read669(file) && !ReadFAR(file) - && !ReadAMS(lpStream, dwMemLength) + && !ReadAMS(file) && !ReadAMS2(file) && !ReadOKT(file) && !ReadPTM(lpStream, dwMemLength) @@ -1954,13 +1954,7 @@ delete Instruments[instr]; - try - { - return (Instruments[instr] = new ModInstrument(assignedSample)); - } catch(MPTMemoryException) - { - return (Instruments[instr] = nullptr); - } + return (Instruments[instr] = new (std::nothrow) ModInstrument(assignedSample)); } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-06-18 21:00:54 UTC (rev 1304) @@ -382,7 +382,7 @@ bool ReadWav(FileReader &file); bool ReadDSM(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadFAR(FileReader &file); - bool ReadAMS(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadAMS(FileReader &file); bool ReadAMS2(FileReader &file); bool ReadMDL(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadOKT(FileReader &file); Modified: trunk/OpenMPT/soundlib/modcommand.cpp =================================================================== --- trunk/OpenMPT/soundlib/modcommand.cpp 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/soundlib/modcommand.cpp 2012-06-18 21:00:54 UTC (rev 1304) @@ -932,4 +932,38 @@ return false; } return true; -} \ No newline at end of file +} + +// Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. +bool ModCommand::CombineEffects(uint8 &eff1, uint8 ¶m1, uint8 &eff2, uint8 ¶m2) +{ + if(eff1 == CMD_VOLUMESLIDE && (eff2 == CMD_VIBRATO || eff2 == CMD_TONEPORTAVOL) && param2 == 0) + { + // Merge commands + if(eff2 == CMD_VIBRATO) + { + eff1 = CMD_VIBRATOVOL; + } else + { + eff1 = CMD_TONEPORTAVOL; + } + eff2 = CMD_NONE; + return true; + } else if(eff2 == CMD_VOLUMESLIDE && (eff1 == CMD_VIBRATO || eff1 == CMD_TONEPORTAVOL) && param1 == 0) + { + // Merge commands + if(eff1 == CMD_VIBRATO) + { + eff1 = CMD_VIBRATOVOL; + } else + { + eff1 = CMD_TONEPORTAVOL; + } + param1 = param2; + eff2 = CMD_NONE; + return true; + } else + { + return false; + } +} Modified: trunk/OpenMPT/soundlib/modcommand.h =================================================================== --- trunk/OpenMPT/soundlib/modcommand.h 2012-06-18 00:42:57 UTC (rev 1303) +++ trunk/OpenMPT/soundlib/modcommand.h 2012-06-18 21:00:54 UTC (rev 1304) @@ -95,8 +95,10 @@ // "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(COMMAND cmd); - // try to convert a an effect into a volume column effect. + // Try to convert a an effect into a volume column effect. Returns true on success. static bool ConvertVolEffect(uint8 &effect, uint8 ¶m, bool force); + // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. + static bool CombineEffects(uint8 &eff1, uint8 ¶m1, uint8 &eff2, uint8 ¶m2); // Swap volume and effect column (doesn't do any conversion as it's mainly for importing formats with multiple effect columns, so beware!) void SwapEffects() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-06-23 14:36:07
|
Revision: 1305 http://modplug.svn.sourceforge.net/modplug/?rev=1305&view=rev Author: saga-games Date: 2012-06-23 14:35:59 +0000 (Sat, 23 Jun 2012) Log Message: ----------- [Ref] Rewrote ITP loader. [Mod] Uninstaller: Tried to removes crash reports generated by OpenMPT now. [Mod] OpenMPT: Version is now 1.20.01.09 Modified Paths: -------------- trunk/OpenMPT/installer/install.iss trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Message.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/pattern.cpp trunk/OpenMPT/soundlib/pattern.h Modified: trunk/OpenMPT/installer/install.iss =================================================================== --- trunk/OpenMPT/installer/install.iss 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/installer/install.iss 2012-06-23 14:35:59 UTC (rev 1305) @@ -281,6 +281,13 @@ DeleteFile(filepath + 'Keybindings.mkb'); DeleteFile(filepath + 'plugin.cache'); DeleteFile(filepath + 'tunings\local_tunings.tc'); + + filepath := GetTempDir(); + if(filepath <> '') then + begin + filepath := filepath + 'OpenMPT Crash Files\'; + DelTree(filepath, True, True, True); + end; end; end; end; Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/mptrack/version.h 2012-06-23 14:35:59 UTC (rev 1305) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 01 -#define VER_MINORMINOR 08 +#define VER_MINORMINOR 09 //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_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2012-06-23 14:35:59 UTC (rev 1305) @@ -21,400 +21,230 @@ #define ITP_VERSION 0x00000102 // v1.02 -#define ITP_FILE_ID 0x2e697470 // .itp ASCII +#define ITP_FILE_ID 0x2E697470 // .itp ASCII -bool CSoundFile::ReadITProject(LPCBYTE lpStream, const DWORD dwMemLength) -//----------------------------------------------------------------------- +// Read variable-length ITP string. +template<size_t destSize> +bool ReadITPString(char (&destBuffer)[destSize], FileReader &file) +//---------------------------------------------------------------- { - UINT i,n,nsmp; - DWORD id,len,size; - DWORD dwMemPos = 0; - DWORD version; + return file.ReadString<StringFixer::maybeNullTerminated>(destBuffer, file.ReadUint32LE()); +} - ASSERT_CAN_READ(12); - // Check file ID +bool CSoundFile::ReadITProject(FileReader &file) +//---------------------------------------------- +{ + uint32 version; + size_t size; - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - if(id != ITP_FILE_ID) return false; - dwMemPos += sizeof(DWORD); + file.Rewind(); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - version = id; - dwMemPos += sizeof(DWORD); - - // max supported version - if(version > ITP_VERSION) + // Check file ID + if(file.BytesLeft() < 12 + 4 + 24 + 4 + || file.ReadUint32LE() != ITP_FILE_ID // Magic bytes + || (version = file.ReadUint32LE()) > ITP_VERSION // Format version + || !ReadITPString(m_szNames[0], file)) // Song name { return false; } - m_nType = MOD_TYPE_IT; + // Song comments + ReadMessage(file, file.ReadUint32LE(), leCR); - // Song name - - // name string length - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - len = id; - dwMemPos += sizeof(DWORD); - - // name string - ASSERT_CAN_READ(len); - if (len<=sizeof(m_szNames[0])) + // Song global config + m_dwSongFlags = (file.ReadUint32LE() & SONG_FILE_FLAGS); + if(!(m_dwSongFlags & SONG_ITPROJECT)) { - memcpy(m_szNames[0],lpStream+dwMemPos,len); - dwMemPos += len; - StringFixer::SetNullTerminator(m_szNames[0]); + return false; } - else return false; - // Song comments - - // comment string length - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - dwMemPos += sizeof(DWORD); - if(id > uint16_max) return false; - - // allocate and copy comment string - ASSERT_CAN_READ(id); - if(id > 0) + m_nDefaultGlobalVolume = file.ReadUint32LE(); + m_nSamplePreAmp = file.ReadUint32LE(); + m_nDefaultSpeed = file.ReadUint32LE(); + m_nDefaultTempo = file.ReadUint32LE(); + m_nChannels = static_cast<CHANNELINDEX>(file.ReadUint32LE()); + if(m_nChannels == 0 || m_nChannels > MAX_BASECHANNELS) { - ReadMessage(lpStream + dwMemPos, id - 1, leCR); + return false; } - dwMemPos += id; - // Song global config - ASSERT_CAN_READ(5*4); - - // m_dwSongFlags - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_dwSongFlags = (id & SONG_FILE_FLAGS); - dwMemPos += sizeof(DWORD); - - if(!(m_dwSongFlags & SONG_ITPROJECT)) return false; - - // m_nDefaultGlobalVolume - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_nDefaultGlobalVolume = id; - dwMemPos += sizeof(DWORD); - - // m_nSamplePreAmp - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_nSamplePreAmp = id; - dwMemPos += sizeof(DWORD); - - // m_nDefaultSpeed - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_nDefaultSpeed = id; - dwMemPos += sizeof(DWORD); - - // m_nDefaultTempo - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_nDefaultTempo = id; - dwMemPos += sizeof(DWORD); - - // Song channels data - ASSERT_CAN_READ(2*4); - - // m_nChannels - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_nChannels = (CHANNELINDEX)id; - dwMemPos += sizeof(DWORD); - if(m_nChannels > 127) return false; - // channel name string length (=MAX_CHANNELNAME) - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - len = id; - dwMemPos += sizeof(DWORD); - if(len > MAX_CHANNELNAME) return false; + size = file.ReadUint32LE(); // Channels' data - for(i=0; i<m_nChannels; i++){ - ASSERT_CAN_READ(3*4 + len); - - // ChnSettings[i].nPan - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - ChnSettings[i].nPan = id; - dwMemPos += sizeof(DWORD); - - // ChnSettings[i].dwFlags - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - ChnSettings[i].dwFlags = id; - dwMemPos += sizeof(DWORD); - - // ChnSettings[i].nVolume - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - ChnSettings[i].nVolume = id; - dwMemPos += sizeof(DWORD); - - // ChnSettings[i].szName - memcpy(&ChnSettings[i].szName[0],lpStream+dwMemPos,len); - StringFixer::SetNullTerminator(ChnSettings[i].szName); - dwMemPos += len; + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + { + ChnSettings[chn].nPan = static_cast<uint16>(file.ReadUint32LE()); + ChnSettings[chn].dwFlags = file.ReadUint32LE(); + ChnSettings[chn].nVolume = static_cast<uint16>(file.ReadUint32LE()); + file.ReadString<StringFixer::maybeNullTerminated>(ChnSettings[chn].szName, size); } // Song mix plugins - // size of mix plugins data - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - dwMemPos += sizeof(DWORD); + size = Util::Min(file.ReadUint32LE(), file.BytesLeft()); + file.Skip(LoadMixPlugins(file.GetRawData(), size)); - // mix plugins - ASSERT_CAN_READ(id); - dwMemPos += LoadMixPlugins(lpStream+dwMemPos, id); - - // Song midi config - - // midi cfg data length - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - dwMemPos += sizeof(DWORD); - - // midi cfg - ASSERT_CAN_READ(id); - if (id <= sizeof(m_MidiCfg)) + // MIDI Macro config + file.ReadStructPartial(m_MidiCfg, file.ReadUint32LE()); + if(m_dwSongFlags & SONG_EMBEDMIDICFG) { - memcpy(&m_MidiCfg, lpStream + dwMemPos, id); m_MidiCfg.Sanitize(); - dwMemPos += id; + } else + { + m_MidiCfg.Reset(); } // Song Instruments + m_nInstruments = static_cast<INSTRUMENTINDEX>(file.ReadUint32LE()); + if(m_nInstruments >= MAX_INSTRUMENTS) + { + return false; + } - // m_nInstruments - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - m_nInstruments = (INSTRUMENTINDEX)id; - if(m_nInstruments > MAX_INSTRUMENTS) return false; - dwMemPos += sizeof(DWORD); - - // path string length (=_MAX_PATH) - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - len = id; - if(len > _MAX_PATH) return false; - dwMemPos += sizeof(DWORD); - - // instruments' paths - for(i=0; i<m_nInstruments; i++){ - ASSERT_CAN_READ(len); - memcpy(&m_szInstrumentPath[i][0],lpStream+dwMemPos,len); - StringFixer::SetNullTerminator(m_szInstrumentPath[i]); - dwMemPos += len; + // Instruments' paths + size = file.ReadUint32LE(); // path string length + for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) + { + file.ReadString<StringFixer::maybeNullTerminated>(m_szInstrumentPath[ins], size); } // Song Orders + Order.ReadAsByte(file, file.ReadUint32LE()); - // size of order array (=MAX_ORDERS) - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - size = id; - if(size > MAX_ORDERS) return false; - dwMemPos += sizeof(DWORD); - - // order data - ASSERT_CAN_READ(size); - Order.ReadAsByte(lpStream+dwMemPos, size, dwMemLength-dwMemPos); - dwMemPos += size; - - - // Song Patterns + const PATTERNINDEX numPats = static_cast<PATTERNINDEX>(file.ReadUint32LE()); + const PATTERNINDEX numNamedPats = static_cast<PATTERNINDEX>(file.ReadUint32LE()); + size_t patNameLen = file.ReadUint32LE(); // Size of each pattern name + FileReader pattNames = file.GetChunk(numNamedPats * patNameLen); - ASSERT_CAN_READ(3*4); - // number of patterns (=MAX_PATTERNS) - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - size = id; - dwMemPos += sizeof(DWORD); - if(size > MAX_PATTERNS) return false; - // m_nPatternNames - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - const PATTERNINDEX numNamedPats = static_cast<PATTERNINDEX>(id); - dwMemPos += sizeof(DWORD); - - // pattern name string length (=MAX_PATTERNNAME) - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - const DWORD patNameLen = id; - dwMemPos += sizeof(DWORD); - - // m_lpszPatternNames - ASSERT_CAN_READ(numNamedPats * patNameLen); - char *patNames = (char *)(lpStream + dwMemPos); - dwMemPos += numNamedPats * patNameLen; - // modcommand data length - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - n = id; - if(n != 6) return false; - dwMemPos += sizeof(DWORD); + size = file.ReadUint32LE(); + if(size != 6) + { + return false; + } - for(PATTERNINDEX npat=0; npat<size; npat++) + for(PATTERNINDEX pat = 0; pat < numPats; pat++) { // Patterns[npat].GetNumRows() - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - if(id > MAX_PATTERN_ROWS) return false; - const ROWINDEX nRows = id; - dwMemPos += sizeof(DWORD); + const ROWINDEX numRows = file.ReadUint32LE(); + FileReader patternChunk = file.GetChunk(numRows * size * GetNumChannels()); - // Try to allocate & read only sized patterns - if(nRows) + // Allocate pattern + if(numRows == 0 || numRows > MAX_PATTERN_ROWS || Patterns.Insert(pat, numRows)) { + pattNames.Skip(patNameLen); + continue; + } - // Allocate pattern - if(Patterns.Insert(npat, nRows)) - { - dwMemPos += m_nChannels * Patterns[npat].GetNumRows() * n; - continue; - } - if(npat < numNamedPats && patNameLen > 0) - { - Patterns[npat].SetName(patNames, patNameLen); - patNames += patNameLen; - } + if(pat < numNamedPats) + { + char patName[MAX_PATTERNNAME]; + pattNames.ReadString<StringFixer::maybeNullTerminated>(patName, patNameLen); + Patterns[pat].SetName(patName); + } - // Pattern data - long datasize = m_nChannels * Patterns[npat].GetNumRows() * n; - //if (streamPos+datasize<=dwMemLength) { - if(Patterns[npat].ReadITPdata(lpStream, dwMemPos, datasize, dwMemLength)) + // Pattern data + size_t numCommands = GetNumChannels() * numRows; + + if(patternChunk.CanRead(sizeof(MODCOMMAND_ORIGINAL) * numCommands)) + { + ModCommand *target = Patterns[pat].GetpModCommand(0, 0); + while(numCommands-- != 0) { - ErrorBox(IDS_ERR_FILEOPEN, NULL); - return false; + MODCOMMAND_ORIGINAL data; + patternChunk.Read(data); + *(target++) = data; } - //memcpy(Patterns[npat],lpStream+streamPos,datasize); - //streamPos += datasize; - //} } } // Load embeded samples // Read original number of samples - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - if(id >= MAX_SAMPLES) return false; - m_nSamples = (SAMPLEINDEX)id; - dwMemPos += sizeof(DWORD); + m_nSamples = static_cast<SAMPLEINDEX>(file.ReadUint32LE()); + LimitMax(m_nSamples, SAMPLEINDEX(MAX_SAMPLES - 1)); // Read number of embeded samples - ASSERT_CAN_READ(4); - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - if(id > MAX_SAMPLES) return false; - n = id; - dwMemPos += sizeof(DWORD); + uint32 embeddedSamples = file.ReadUint32LE(); // Read samples - for(i=0; i<n; i++) + for(uint32 smp = 0; smp < embeddedSamples; smp++) { + SAMPLEINDEX realSample = static_cast<SAMPLEINDEX>(file.ReadUint32LE()); + ITSample sampleHeader; + file.Read(sampleHeader); + size = file.ReadUint32LE(); - ASSERT_CAN_READ(4 + sizeof(ITSample) + 4); - - // Sample id number - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - nsmp = id; - dwMemPos += sizeof(DWORD); - - if(nsmp < 1 || nsmp >= MAX_SAMPLES) - return false; - - // Sample struct - ITSample pis; - memcpy(&pis, lpStream + dwMemPos, sizeof(ITSample)); - dwMemPos += sizeof(ITSample); - - // Sample length - memcpy(&id,lpStream+dwMemPos,sizeof(DWORD)); - len = id; - dwMemPos += sizeof(DWORD); - if(dwMemPos >= dwMemLength || len > dwMemLength - dwMemPos) return false; - - if(pis.id == LittleEndian(ITSample::magic)) + if(realSample >= 1 && realSample < MAX_SAMPLES && sampleHeader.id == LittleEndian(ITSample::magic)) { - pis.ConvertToMPT(Samples[nsmp]); + sampleHeader.ConvertToMPT(Samples[realSample]); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[realSample], sampleHeader.name); - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[nsmp], pis.name); - // Read sample data - pis.GetSampleFormat().ReadSample(Samples[nsmp], (LPSTR)(lpStream + dwMemPos), len); - dwMemPos += len; + sampleHeader.GetSampleFormat().ReadSample(Samples[realSample], file); + } else + { + file.Skip(size); } } // Load instruments - CMappedFile f; - LPBYTE lpFile; - for(INSTRUMENTINDEX i = 0; i < m_nInstruments; i++) + for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) { + if(m_szInstrumentPath[ins][0] == '\0' || !f.Open(m_szInstrumentPath[ins])) continue; - if(m_szInstrumentPath[i][0] == '\0' || !f.Open(m_szInstrumentPath[i])) continue; - - len = f.GetLength(); - lpFile = f.Lock(len); + size = f.GetLength(); + LPBYTE lpFile = f.Lock(size); if(!lpFile) { f.Close(); continue; } - ReadInstrumentFromFile(i+1, lpFile, len); + ReadInstrumentFromFile(ins + 1, lpFile, size); f.Unlock(); f.Close(); } // Extra info data + uint32 code = file.ReadUint32LE(); - __int32 fcode = 0; - LPCBYTE ptr = lpStream + min(dwMemPos, dwMemLength); - - if (dwMemPos <= dwMemLength - 4) { - fcode = (*((__int32 *)ptr)); - } - // Embed instruments' header [v1.01] - if(version >= 0x00000101 && m_dwSongFlags & SONG_ITPEMBEDIH && fcode == 'EBIH') + if(version >= 0x00000101 && (m_dwSongFlags & SONG_ITPEMBEDIH) && code == 'EBIH') { - // jump embeded instrument header tag - ptr += sizeof(__int32); + code = file.ReadUint32LE(); - // set first instrument's header as current - i = 1; - - // parse file - while( uintptr_t(ptr - lpStream) <= dwMemLength - 4 && i <= m_nInstruments ) + INSTRUMENTINDEX ins = 1; + while(ins <= GetNumInstruments() && file.BytesLeft()) { - - fcode = (*((__int32 *)ptr)); // read field code - - switch( fcode ) + if(code == 'MPTS') { - case 'MPTS': goto mpts; //:) // reached end of instrument headers - case 'SEP@': case 'MPTX': - ptr += sizeof(__int32); // jump code - i++; // switch to next instrument break; - - default: - ptr += sizeof(__int32); // jump field code - ReadExtendedInstrumentProperty(Instruments[i], fcode, ptr, lpStream + dwMemLength); - break; + } else if(code == 'SEP@' || code == 'MPTX') + { + // jump code - switch to next instrument + ins++; + } else + { + const uint8 *pos = reinterpret_cast<const uint8 *>(file.GetRawData()); + ReadExtendedInstrumentProperty(Instruments[ins], code, pos, pos + file.BytesLeft()); + file.Skip(pos - reinterpret_cast<const uint8 *>(file.GetRawData())); } + + code = file.ReadUint32LE(); } } - //HACK: if we fail on i <= m_nInstruments above, arrive here without having set fcode as appropriate, - // hence the code duplication. - if ( (uintptr_t)(ptr - lpStream) <= dwMemLength - 4 ) + // Song extensions + if(code == 'MPTS') { - fcode = (*((__int32 *)ptr)); + const uint8 *data = reinterpret_cast<const uint8 *>(file.GetRawData()) - 4; + LoadExtendedSongProperties(MOD_TYPE_IT, data, data, file.BytesLeft() + 4); } - // Song extensions -mpts: - if( fcode == 'MPTS' ) - LoadExtendedSongProperties(MOD_TYPE_IT, ptr, lpStream, dwMemLength); - + m_nType = MOD_TYPE_IT; m_nMaxPeriod = 0xF000; m_nMinPeriod = 8; @@ -516,11 +346,11 @@ // Song midi config // midi cfg data length - id = sizeof(MIDIMacroConfig); + id = (m_dwSongFlags & SONG_EMBEDMIDICFG) ? sizeof(MIDIMacroConfig) : 0; fwrite(&id, 1, sizeof(id), f); // midi cfg - fwrite(&m_MidiCfg, 1, sizeof(MIDIMacroConfig), f); + fwrite(&m_MidiCfg, 1, id, f); // Song Instruments @@ -640,8 +470,8 @@ if(m_dwSongFlags & SONG_ITPEMBEDIH) { // embeded instrument header tag - __int32 code = 'EBIH'; - fwrite(&code, 1, sizeof(__int32), f); + uint32 code = 'EBIH'; + fwrite(&code, 1, sizeof(uint32), f); // instruments' header for(i=0; i<m_nInstruments; i++) @@ -649,7 +479,7 @@ if(Instruments[i+1]) WriteInstrumentHeaderStruct(Instruments[i+1], f); // write separator tag code = 'SEP@'; - fwrite(&code, 1, sizeof(__int32), f); + fwrite(&code, 1, sizeof(uint32), f); } } Modified: trunk/OpenMPT/soundlib/Message.cpp =================================================================== --- trunk/OpenMPT/soundlib/Message.cpp 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/soundlib/Message.cpp 2012-06-23 14:35:59 UTC (rev 1305) @@ -51,9 +51,15 @@ // [in] lineEnding: line ending formatting of the text in memory. // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). // [out] returns true on success. -bool CSoundFile::ReadMessage(const BYTE *data, const size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &)) -//---------------------------------------------------------------------------------------------------------------------------- +bool CSoundFile::ReadMessage(const BYTE *data, size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &)) +//---------------------------------------------------------------------------------------------------------------------- { + if(length != 0 && data[length - 1] == '\0') + { + // Ignore trailing null character. + length--; + } + char c; // Simple line-ending detection algorithm. VERY simple. @@ -85,7 +91,7 @@ lineEnding = leMixed; } - size_t final_length = 0; + size_t finalLength = 0; // calculate the final amount of characters to be allocated. for(size_t i = 0; i < length; i++) { @@ -94,10 +100,10 @@ pTextConverter(c); if(c != '\n' || lineEnding != leCRLF) - final_length++; + finalLength++; } - if(!AllocateMessage(final_length)) + if(!AllocateMessage(finalLength)) return false; size_t cpos = 0; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-06-23 14:35:59 UTC (rev 1305) @@ -590,7 +590,7 @@ if(!ReadXM(lpStream, dwMemLength) // -> CODE#0023 // -> DESC="IT project files (.itp)" - && !ReadITProject(lpStream, dwMemLength) + && !ReadITProject(file) // -! NEW_FEATURE#0023 && !ReadIT(lpStream, dwMemLength) /*&& !ReadMPT(lpStream, dwMemLength)*/ Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-06-23 14:35:59 UTC (rev 1305) @@ -375,8 +375,7 @@ bool ReadMTM(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadSTM(FileReader &file); bool ReadIT(const LPCBYTE lpStream, const DWORD dwMemLength); - //bool ReadMPT(const LPCBYTE lpStream, const DWORD dwMemLength); - bool ReadITProject(const LPCBYTE lpStream, const DWORD dwMemLength); // -> CODE#0023 -> DESC="IT project files (.itp)" -! NEW_FEATURE#0023 + bool ReadITProject(FileReader &file); bool Read669(FileReader &file); bool ReadUlt(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadWav(FileReader &file); @@ -685,8 +684,8 @@ // [in] lineEnding: line ending formatting of the text in memory. // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). // [out] returns true on success. - bool ReadMessage(const BYTE *data, const size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr); - bool ReadMessage(FileReader &file, const size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr) + bool ReadMessage(const BYTE *data, size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr); + bool ReadMessage(FileReader &file, size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr) { size_t readLength = Util::Min(length, file.BytesLeft()); bool success = ReadMessage(reinterpret_cast<const BYTE*>(file.GetRawData()), readLength, lineEnding, pTextConverter); Modified: trunk/OpenMPT/soundlib/pattern.cpp =================================================================== --- trunk/OpenMPT/soundlib/pattern.cpp 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/soundlib/pattern.cpp 2012-06-23 14:35:59 UTC (rev 1305) @@ -455,40 +455,7 @@ return false; } -bool CPattern::ReadITPdata(const BYTE* const lpStream, DWORD& streamPos, const DWORD datasize, const DWORD dwMemLength) -//----------------------------------------------------------------------------------------------- -{ - if(streamPos > dwMemLength || datasize >= dwMemLength - streamPos || datasize < sizeof(MODCOMMAND_ORIGINAL)) - return true; - const DWORD startPos = streamPos; - size_t counter = 0; - while(streamPos - startPos + sizeof(MODCOMMAND_ORIGINAL) <= datasize) - { - MODCOMMAND_ORIGINAL temp; - memcpy(&temp, lpStream + streamPos, sizeof(MODCOMMAND_ORIGINAL)); - ModCommand& mc = GetModCommand(counter); - mc.command = temp.command; - mc.instr = temp.instr; - mc.note = temp.note; - mc.param = temp.param; - mc.vol = temp.vol; - mc.volcmd = temp.volcmd; - streamPos += sizeof(MODCOMMAND_ORIGINAL); - counter++; - } - if(streamPos != startPos + datasize) - { - ASSERT(false); - return true; - } - else - return false; -} - - - - //////////////////////////////////////////////////////////////////////// // // Pattern serialization functions Modified: trunk/OpenMPT/soundlib/pattern.h =================================================================== --- trunk/OpenMPT/soundlib/pattern.h 2012-06-18 21:00:54 UTC (rev 1304) +++ trunk/OpenMPT/soundlib/pattern.h 2012-06-23 14:35:59 UTC (rev 1305) @@ -117,13 +117,6 @@ bool WriteEffect(EffectWriter &settings); bool WriteITPdata(FILE* f) const; - bool ReadITPdata(const BYTE* const lpStream, DWORD& streamPos, const DWORD datasize, const DWORD dwMemLength); - //Parameters: - //1. Pointer to the beginning of the stream - //2. Tells where to start(lpStream+streamPos) and number of bytes read is added to it. - //3. How many bytes to read - //4. Length of the stream. - //Returns true on error. // Static allocation / deallocation helpers static ModCommand *AllocatePattern(ROWINDEX rows, CHANNELINDEX nchns); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |