From: <sag...@us...> - 2015-03-11 14:16:07
|
Revision: 4862 http://sourceforge.net/p/modplug/code/4862 Author: saga-games Date: 2015-03-11 14:15:51 +0000 (Wed, 11 Mar 2015) Log Message: ----------- [Mod] The MPTM volume column offset command has been revamped: In the sample editor, 9 custom cue points can be selected for each sample, which can then be triggered using o01... o09. [Mod] Related changes (e.g. showing proper value readout for volume column effects in the note properties) [Mod] OpenMPT: Version is now 1.24.02.06 Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/common/versionNumber.h trunk/OpenMPT/mptrack/AppendModule.cpp trunk/OpenMPT/mptrack/CommandSet.cpp trunk/OpenMPT/mptrack/CommandSet.h trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/Draw_pat.cpp trunk/OpenMPT/mptrack/EffectInfo.cpp trunk/OpenMPT/mptrack/EffectInfo.h trunk/OpenMPT/mptrack/KeyConfigDlg.cpp trunk/OpenMPT/mptrack/MPTrackUtil.h trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/PatternClipboard.cpp trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp trunk/OpenMPT/mptrack/PatternEditorDialogs.h trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/mptrack/View_smp.h trunk/OpenMPT/mptrack/mptrack.rc trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb trunk/OpenMPT/mptrack/resource.h trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_mt2.cpp trunk/OpenMPT/soundlib/Load_mtm.cpp trunk/OpenMPT/soundlib/ModChannel.h trunk/OpenMPT/soundlib/ModSample.cpp trunk/OpenMPT/soundlib/ModSample.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp trunk/OpenMPT/soundlib/WAVTools.cpp trunk/OpenMPT/soundlib/WAVTools.h trunk/OpenMPT/soundlib/modcommand.cpp trunk/OpenMPT/soundlib/modcommand.h trunk/OpenMPT/soundlib/modsmp_ctrl.cpp trunk/OpenMPT/soundlib/modsmp_ctrl.h trunk/OpenMPT/test/test.cpp trunk/OpenMPT/test/test.mptm Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/common/misc_util.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -574,6 +574,71 @@ return (x / target) * target; } + // Insert a range of items [insStart, insEnd], and possibly shift item fix to the left. + template<typename T> + void InsertItem(const T insStart, const T insEnd, T &fix) + { + ASSERT(insEnd >= insStart); + if(fix >= insStart) + { + fix += (insEnd - insStart + 1); + } + } + + // Insert a range of items [insStart, insEnd], and possibly shift items in range [fixStart, fixEnd] to the right. + template<typename T> + void InsertRange(const T insStart, const T insEnd, T &fixStart, T &fixEnd) + { + ASSERT(insEnd >= insStart); + const T insLength = insEnd - insStart + 1; + if(fixStart >= insEnd) + { + fixStart += insLength; + } + if(fixEnd >= insEnd) + { + fixEnd += insLength; + } + } + + // Delete a range of items [delStart, delEnd], and possibly shift item fix to the left. + template<typename T> + void DeleteItem(const T delStart, const T delEnd, T &fix) + { + ASSERT(delEnd >= delStart); + if(fix > delEnd) + { + fix -= (delEnd - delStart + 1); + } + } + + // Delete a range of items [delStart, delEnd], and possibly shift items in range [fixStart, fixEnd] to the left. + template<typename T> + void DeleteRange(const T delStart, const T delEnd, T &fixStart, T &fixEnd) + { + ASSERT(delEnd >= delStart); + const T delLength = delEnd - delStart + 1; + if(delStart < fixStart && delEnd < fixStart) + { + // cut part is before loop start + fixStart -= delLength; + fixEnd -= delLength; + } else if(delStart < fixStart && delEnd < fixEnd) + { + // cut part is partly before loop start + fixStart = delStart; + fixEnd -= delLength; + } else if(delStart >= fixStart && delEnd < fixEnd) + { + // cut part is in the loop + fixEnd -= delLength; + } else if(delStart >= fixStart && delStart < fixEnd && delEnd > fixEnd) + { + // cut part is partly before loop end + fixEnd = delStart; + } + } + // Greatest Common Divisor. Always returns non-negative number. template <class T> T gcd(T a, T b) Modified: trunk/OpenMPT/common/versionNumber.h =================================================================== --- trunk/OpenMPT/common/versionNumber.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/common/versionNumber.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 24 #define VER_MINOR 02 -#define VER_MINORMINOR 05 +#define VER_MINORMINOR 06 //Version string. For example "1.17.02.28" #define MPT_VERSION_STR VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR) Modified: trunk/OpenMPT/mptrack/AppendModule.cpp =================================================================== --- trunk/OpenMPT/mptrack/AppendModule.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/AppendModule.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -272,7 +272,7 @@ for(CHANNELINDEX chn = 0; chn < copyChannels; chn++, src++, m++) { *m = *src; - m->Convert(source.GetType(), m_SndFile.GetType()); + m->Convert(source.GetType(), m_SndFile.GetType(), source); if(m->IsPcNote()) { if(m->instr && m->instr < pluginMapping.size()) m->instr = static_cast<ModCommand::INSTR>(pluginMapping[m->instr]); Modified: trunk/OpenMPT/mptrack/CommandSet.cpp =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/CommandSet.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -471,7 +471,7 @@ DefineKeyCommand(kcSampleZoomUp, 1386, _T("Zoom Out")); DefineKeyCommand(kcSampleZoomDown, 1387, _T("Zoom In")); //time saving HACK: - for(size_t j = kcSampStartNotes; j <= kcInsNoteMapEndNoteStops; j++) + for(int j = kcSampStartNotes; j <= kcInsNoteMapEndNoteStops; j++) { DefineKeyCommand((CommandID)j, 1388 + j - kcSampStartNotes, _T("Auto Note in some context"), kcHidden, kcNoDummy); } @@ -511,7 +511,7 @@ DefineKeyCommand(kcPrevDocument, 1693, _T("Previous Document")); DefineKeyCommand(kcNextDocument, 1694, _T("Next Document")); //time saving HACK: - for(size_t j = kcVSTGUIStartNotes; j <= kcVSTGUIEndNoteStops; j++) + for(int j = kcVSTGUIStartNotes; j <= kcVSTGUIEndNoteStops; j++) { DefineKeyCommand((CommandID)j, 1695 + j - kcVSTGUIStartNotes, _T("Auto Note in some context"), kcHidden, kcNoDummy); } @@ -678,6 +678,12 @@ DefineKeyCommand(kcInstrumentEnvelopeSave, 1921, _T("Save Envelope")); DefineKeyCommand(kcChannelTranspose, 1922, _T("Transpose Channel")); DefineKeyCommand(kcChannelDuplicate, 1923, _T("Duplicate Channel")); + for(int j = kcStartSampleCues; j <= kcEndSampleCues; j++) + { + TCHAR s[32]; + wsprintf(s, "Preview Sample Cue %u", j - kcStartSampleCues + 1); + DefineKeyCommand((CommandID)j, 1924 + j - kcStartSampleCues, s); + } Modified: trunk/OpenMPT/mptrack/CommandSet.h =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/CommandSet.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -699,6 +699,9 @@ kcSampleAutotune, kcEndSampleEditing=kcSampleAutotune, + kcStartSampleCues, + kcEndSampleCues = kcStartSampleCues + 8, + //kcSampStartNotes to kcInsNoteMapEndNoteStops must be contiguous. kcSampStartNotes, kcSampNoteC_0=kcSampStartNotes, Modified: trunk/OpenMPT/mptrack/Ctrl_seq.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -331,10 +331,7 @@ if(isPlaying && sndFile.m_SongFlags[SONG_PATTERNLOOP]) { - sndFile.m_PlayState.m_nPattern = n; - sndFile.m_PlayState.m_nCurrentOrder = sndFile.m_PlayState.m_nNextOrder = m_nScrollPos; pMainFrm->ResetNotificationBuffer(); - sndFile.m_PlayState.m_nNextRow = 0; // update channel parameters and play time m_pModDoc.SetElapsedTime(m_nScrollPos, 0, !sndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]); @@ -343,13 +340,9 @@ } else if(m_pParent.GetFollowSong()) { FlagSet<SongFlags> pausedFlags = sndFile.m_SongFlags & (SONG_PAUSED | SONG_STEP | SONG_PATTERNLOOP); - - sndFile.m_PlayState.m_nCurrentOrder = m_nScrollPos; - sndFile.SetCurrentOrder(m_nScrollPos); - sndFile.m_SongFlags.set(pausedFlags); - // update channel parameters and play time m_pModDoc.SetElapsedTime(m_nScrollPos, 0, !sndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]); + sndFile.m_SongFlags.set(pausedFlags); if(isPlaying) pMainFrm->ResetNotificationBuffer(); changedPos = true; Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Draw_pat.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/Draw_pat.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -1601,7 +1601,9 @@ // "normal" volume command TCHAR sztmp[64] = ""; effectInfo.GetVolCmdInfo(effectInfo.GetIndexFromVolCmd(m->volcmd), sztmp); - s.Format("%s (%u)", sztmp, m->vol); + _tcscat(sztmp, _T(": ")); + effectInfo.GetVolCmdParamInfo(*m, sztmp + strlen(sztmp)); + s = sztmp; } break; Modified: trunk/OpenMPT/mptrack/EffectInfo.cpp =================================================================== --- trunk/OpenMPT/mptrack/EffectInfo.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/EffectInfo.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -876,7 +876,7 @@ {VOLCMD_PORTAUP, MOD_TYPE_ITMPT, "Portamento up"}, {VOLCMD_PORTADOWN, MOD_TYPE_ITMPT, "Portamento down"}, {VOLCMD_DELAYCUT, MOD_TYPE_NONE, ""}, - {VOLCMD_OFFSET, MOD_TYPE_MPT, "Offset"}, + {VOLCMD_OFFSET, MOD_TYPE_MPT, "Sample Cue"}, }; STATIC_ASSERT(CountOf(gVolCmdInfo) == (MAX_VOLCMDS - 1)); @@ -935,4 +935,80 @@ } +bool EffectInfo::GetVolCmdParamInfo(const ModCommand &m, LPSTR s) const +//--------------------------------------------------------------------- +{ + if(s == nullptr) return false; + s[0] = 0; + + switch(m.volcmd) + { + case VOLCMD_VOLSLIDEUP: + case VOLCMD_VOLSLIDEDOWN: + case VOLCMD_FINEVOLUP: + case VOLCMD_FINEVOLDOWN: + if(m.vol > 0 || sndFile.GetType() == MOD_TYPE_XM) + { + sprintf(s, "%c%u", + (m.volcmd == VOLCMD_VOLSLIDEUP || m.volcmd == VOLCMD_FINEVOLUP) ? '+' : '-', + m.vol); + } else + { + strcpy(s, "continue"); + } + break; + + case VOLCMD_PORTAUP: + case VOLCMD_PORTADOWN: + case VOLCMD_TONEPORTAMENTO: + if(m.vol > 0) + { + ModCommand::PARAM param = m.vol << 2; + ModCommand::COMMAND cmd = CMD_PORTAMENTOUP; + if(m.volcmd == VOLCMD_PORTADOWN) + { + cmd = CMD_PORTAMENTODOWN; + } else if(m.volcmd == VOLCMD_TONEPORTAMENTO) + { + cmd = CMD_TONEPORTAMENTO; + if(sndFile.GetType() != MOD_TYPE_XM) param = ImpulseTrackerPortaVolCmd[m.vol & 0x0F]; + } + sprintf(s, "%u (%c%02X)", + m.vol, + sndFile.GetModSpecifications().GetEffectLetter(static_cast<ModCommand::COMMAND>(m.volcmd == VOLCMD_PORTAUP ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN)), + m.vol << 2); + } else + { + strcpy(s, "continue"); + } + break; + + case VOLCMD_OFFSET: + if(m.vol) + { + SmpLength param; + SAMPLEINDEX smp = m.instr; + if(smp > 0 && smp <= sndFile.GetNumInstruments() && m.IsNote() && sndFile.Instruments[smp] != nullptr) + { + smp = sndFile.Instruments[smp]->Keyboard[m.note - NOTE_MIN]; + } + if(smp > 0 && smp <= sndFile.GetNumSamples() && m.vol > 0 && m.vol <= CountOf(sndFile.GetSample(smp).cues)) + param = sndFile.GetSample(smp).cues[m.vol - 1]; + else + param = m.vol << 11; + sprintf(s, "Cue %u: %u", m.vol, param); + } else + { + strcpy(s, "continue"); + } + break; + + default: + sprintf(s, "%u", m.vol); + break; + } + return true; +} + + OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/mptrack/EffectInfo.h =================================================================== --- trunk/OpenMPT/mptrack/EffectInfo.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/EffectInfo.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -60,6 +60,8 @@ ModCommand::VOLCMD GetVolCmdFromIndex(UINT ndx) const; // Get range information, effect name, etc... from a given effect. bool GetVolCmdInfo(UINT ndx, LPSTR s, ModCommand::VOL *prangeMin = nullptr, ModCommand::VOL *prangeMax = nullptr) const; + // Get effect name and parameter description + bool GetVolCmdParamInfo(const ModCommand &m, LPSTR s) const; }; OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/mptrack/KeyConfigDlg.cpp =================================================================== --- trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -358,6 +358,9 @@ newCat.separators.push_back(kcEndSampleEditing); //-------------------------------------- for(int c = kcStartSampleMisc; c <= kcEndSampleMisc; c++) newCat.commands.push_back(c); + newCat.separators.push_back(kcEndSampleMisc); //-------------------------------------- + for(int c = kcStartSampleCues; c <= kcEndSampleCues; c++) + newCat.commands.push_back(c); commandCategories.push_back(newCat); } Modified: trunk/OpenMPT/mptrack/MPTrackUtil.h =================================================================== --- trunk/OpenMPT/mptrack/MPTrackUtil.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/MPTrackUtil.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -31,71 +31,6 @@ namespace Util { - // Insert a range of items [insStart, insEnd], and possibly shift item fix to the left. - template<typename T> - void InsertItem(const T insStart, const T insEnd, T &fix) - { - ASSERT(insEnd >= insStart); - if(fix >= insStart) - { - fix += (insEnd - insStart + 1); - } - } - - // Insert a range of items [insStart, insEnd], and possibly shift items in range [fixStart, fixEnd] to the right. - template<typename T> - void InsertRange(const T insStart, const T insEnd, T &fixStart, T &fixEnd) - { - ASSERT(insEnd >= insStart); - const T insLength = insEnd - insStart + 1; - if(fixStart >= insEnd) - { - fixStart += insLength; - } - if(fixEnd >= insEnd) - { - fixEnd += insLength; - } - } - - // Delete a range of items [delStart, delEnd], and possibly shift item fix to the left. - template<typename T> - void DeleteItem(const T delStart, const T delEnd, T &fix) - { - ASSERT(delEnd >= delStart); - if(fix > delEnd) - { - fix -= (delEnd - delStart + 1); - } - } - - // Delete a range of items [delStart, delEnd], and possibly shift items in range [fixStart, fixEnd] to the left. - template<typename T> - void DeleteRange(const T delStart, const T delEnd, T &fixStart, T &fixEnd) - { - ASSERT(delEnd >= delStart); - const T delLength = delEnd - delStart + 1; - if(delStart < fixStart && delEnd < fixStart) - { - // cut part is before loop start - fixStart -= delLength; - fixEnd -= delLength; - } else if(delStart < fixStart && delEnd < fixEnd) - { - // cut part is partly before loop start - fixStart = delStart; - fixEnd -= delLength; - } else if(delStart >= fixStart && delEnd < fixEnd) - { - // cut part is in the loop - fixEnd -= delLength; - } else if(delStart >= fixStart && delStart < fixEnd && delEnd > fixEnd) - { - // cut part is partly before loop end - fixEnd = delStart; - } - } - // Get horizontal DPI resolution forceinline int GetDPIx(HWND hwnd) { Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -263,7 +263,7 @@ } } - m->Convert(nOldType, nNewType); + m->Convert(nOldType, nNewType, m_SndFile); // When converting to XM, avoid the E60 bug. if(newTypeIsXM) Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -2417,7 +2417,6 @@ m_SndFile.LoopPattern(nPat); else m_SndFile.LoopPattern(PATTERNINDEX_INVALID); - m_SndFile.m_PlayState.m_nNextRow = 0; // set playback timer in the status bar (and update channel status) SetElapsedTime(nOrd, 0, true); @@ -2472,7 +2471,6 @@ if ((nOrd < m_SndFile.Order.size()) && (m_SndFile.Order[nOrd] == nPat)) m_SndFile.m_PlayState.m_nCurrentOrder = m_SndFile.m_PlayState.m_nNextOrder = nOrd; m_SndFile.m_SongFlags.reset(SONG_PAUSED | SONG_STEP); m_SndFile.LoopPattern(nPat); - m_SndFile.m_PlayState.m_nNextRow = nRow; // set playback timer in the status bar (and update channel status) SetElapsedTime(nOrd, nRow, true); @@ -2530,7 +2528,6 @@ m_SndFile.DontLoopPattern(nPat, nRow); else m_SndFile.LoopPattern(nPat); - m_SndFile.m_PlayState.m_nNextRow = nRow; // set playback timer in the status bar (and update channel status) SetElapsedTime(nOrd, nRow, true); Modified: trunk/OpenMPT/mptrack/PatternClipboard.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternClipboard.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/PatternClipboard.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -759,7 +759,7 @@ // of the old modcommand would falsely be interpreted being of type // origFormat and ConvertCommand could change them. if(pasteFormat != sndFile.GetType() && (!doMixPaste || origModCmd.IsEmpty(false))) - m.Convert(pasteFormat, sndFile.GetType()); + m.Convert(pasteFormat, sndFile.GetType(), sndFile); // Adjust pattern selection if(col == startChan) startPoint.SetColumn(startChan, firstCol); Modified: trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/PatternEditorDialogs.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -896,6 +896,7 @@ sldVolParam.SetPos(0); sldVolParam.EnableWindow(FALSE); } + UpdateVolCmdValue(); } @@ -1008,9 +1009,9 @@ modDoc->UpdateAllViews(NULL, RowHint(editPos.row), NULL); if(volCmdChanged) - { UpdateVolCmdRange(); - } + else + UpdateVolCmdValue(); } } @@ -1071,6 +1072,24 @@ } +void CEditCommand::UpdateVolCmdValue() +//------------------------------------ +{ + CHAR s[64] = ""; + if(m->IsPcNote()) + { + // plugin param control note + uint16 plugParam = static_cast<uint16>(sldVolParam.GetPos()); + wsprintf(s, "Value: %u", plugParam); + } else + { + // process as effect + effectInfo.GetVolCmdParamInfo(*m, s); + } + SetDlgItemText(IDC_TEXT2, s); +} + + void CEditCommand::UpdateEffectValue(bool set) //-------------------------------------------- { Modified: trunk/OpenMPT/mptrack/PatternEditorDialogs.h =================================================================== --- trunk/OpenMPT/mptrack/PatternEditorDialogs.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/PatternEditorDialogs.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -143,6 +143,7 @@ void InitEffect(); void UpdateVolCmdRange(); + void UpdateVolCmdValue(); void UpdateEffectRange(bool set); void UpdateEffectValue(bool set); Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -4730,14 +4730,14 @@ case kcSetVolumeVolSlideDown: volcmd = VOLCMD_VOLSLIDEDOWN; break; case kcSetVolumeFineVolUp: volcmd = VOLCMD_FINEVOLUP; break; case kcSetVolumeFineVolDown: volcmd = VOLCMD_FINEVOLDOWN; break; - case kcSetVolumeVibratoSpd: if (pSndFile->GetType() & MOD_TYPE_XM) volcmd = VOLCMD_VIBRATOSPEED; break; + case kcSetVolumeVibratoSpd: volcmd = VOLCMD_VIBRATOSPEED; break; case kcSetVolumeVibrato: volcmd = VOLCMD_VIBRATODEPTH; break; - case kcSetVolumeXMPanLeft: if (pSndFile->GetType() & MOD_TYPE_XM) volcmd = VOLCMD_PANSLIDELEFT; break; - case kcSetVolumeXMPanRight: if (pSndFile->GetType() & MOD_TYPE_XM) volcmd = VOLCMD_PANSLIDERIGHT; break; + case kcSetVolumeXMPanLeft: volcmd = VOLCMD_PANSLIDELEFT; break; + case kcSetVolumeXMPanRight: volcmd = VOLCMD_PANSLIDERIGHT; break; case kcSetVolumePortamento: volcmd = VOLCMD_TONEPORTAMENTO; break; - case kcSetVolumeITPortaUp: if (pSndFile->GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) volcmd = VOLCMD_PORTAUP; break; - case kcSetVolumeITPortaDown: if (pSndFile->GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) volcmd = VOLCMD_PORTADOWN; break; - case kcSetVolumeITOffset: if (pSndFile->GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) volcmd = VOLCMD_OFFSET; break; //rewbs.volOff + case kcSetVolumeITPortaUp: volcmd = VOLCMD_PORTAUP; break; + case kcSetVolumeITPortaDown: volcmd = VOLCMD_PORTADOWN; break; + case kcSetVolumeITOffset: volcmd = VOLCMD_OFFSET; break; } UINT max = 64; Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -108,6 +108,7 @@ ON_COMMAND(ID_SAMPLE_ADDSILENCE, OnAddSilence) ON_COMMAND(ID_SAMPLE_GRID, OnChangeGridSize) ON_COMMAND(ID_SAMPLE_QUICKFADE, OnQuickFade) + ON_COMMAND_RANGE(ID_SAMPLE_CUE_1, ID_SAMPLE_CUE_9, OnSetCuePoint) ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateUndo) ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateRedo) ON_MESSAGE(WM_MOD_MIDIMSG, OnMidiMsg) @@ -160,6 +161,7 @@ pMainFrm->SetXInfoText(""); } UpdateScrollSize(); + UpdateNcButtonState(); } @@ -1734,8 +1736,8 @@ CModDoc *pModDoc = GetDocument(); if (pModDoc) { - CSoundFile *pSndFile = pModDoc->GetSoundFile(); - const ModSample &sample = pSndFile->GetSample(m_nSample); + const CSoundFile &sndFile = pModDoc->GetrSoundFile(); + const ModSample &sample = sndFile.GetSample(m_nSample); HMENU hMenu = ::CreatePopupMenu(); CInputHandler* ih = (CMainFrame::GetMainFrame())->GetInputHandler(); if (!hMenu) return; @@ -1745,12 +1747,12 @@ { ::AppendMenu(hMenu, MF_STRING | (CanZoomSelection() ? 0 : MF_GRAYED), ID_SAMPLE_ZOOMONSEL, _T("Zoom\t") + ih->GetKeyTextFromCommand(kcSampleZoomSelection)); ::AppendMenu(hMenu, MF_STRING, ID_SAMPLE_SETLOOP, _T("Set As Loop")); - if (pSndFile->GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) + if (sndFile.GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) ::AppendMenu(hMenu, MF_STRING, ID_SAMPLE_SETSUSTAINLOOP, _T("Set As Sustain Loop")); ::AppendMenu(hMenu, MF_SEPARATOR, 0, ""); } else { - CHAR s[256]; + TCHAR s[256]; SmpLength dwPos = ScreenToSample(pt.x); if (dwPos <= sample.nLength) { @@ -1762,7 +1764,7 @@ ::AppendMenu(hMenu, MF_STRING | (dwPos >= sample.nLoopStart + 4 ? 0 : MF_GRAYED), ID_SAMPLE_SETLOOPEND, s); - if (pSndFile->GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) + if (sndFile.GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) { //Set sustain loop points ::AppendMenu(hMenu, MF_SEPARATOR, 0, ""); @@ -1773,6 +1775,20 @@ ::AppendMenu(hMenu, MF_STRING | (dwPos >= sample.nSustainStart + 4 ? 0 : MF_GRAYED), ID_SAMPLE_SETSUSTAINEND, s); } + + if(sndFile.GetModSpecifications().HasVolCommand(VOLCMD_OFFSET)) + { + ::AppendMenu(hMenu, MF_SEPARATOR, 0, _T("")); + HMENU hCueMenu = ::CreatePopupMenu(); + for(int i = 0; i < 9; i++) + { + wsprintf(s, _T("Cue &%c: %u"), '1' + i, sndFile.GetSample(m_nSample).cues[i]); + ::AppendMenu(hCueMenu, MF_STRING, ID_SAMPLE_CUE_1 + i, s); + } + wsprintf(s, _T("Set Sample Cu&e to:\t%u"), dwPos); + ::AppendMenu(hMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(hCueMenu), s); + } + ::AppendMenu(hMenu, MF_SEPARATOR, 0, _T("")); m_dwMenuParam = dwPos; } @@ -1985,19 +2001,6 @@ } -// Update loop points after deleting a sample selection -void CViewSample::AdjustLoopPoints(SmpLength &loopStart, SmpLength &loopEnd, SmpLength length) const -//-------------------------------------------------------------------------------------------------- -{ - Util::DeleteRange(m_dwBeginSel, m_dwEndSel - 1, loopStart, loopEnd); - LimitMax(loopEnd, length); - if(loopStart + 4 >= loopEnd) - { - loopStart = loopEnd = 0; - } -} - - void CViewSample::OnEditDelete() //------------------------------ { @@ -2024,29 +2027,7 @@ pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_delete, "Delete Selection", m_dwBeginSel, m_dwEndSel); CriticalSection cs; - - const SmpLength selStart = m_dwBeginSel * sample.GetBytesPerSample(); - const SmpLength selEnd = m_dwEndSel * sample.GetBytesPerSample(); - const SmpLength smpEnd = sample.nLength * sample.GetBytesPerSample(); - sample.nLength -= (m_dwEndSel - m_dwBeginSel); - - memmove(sample.pSample8 + selStart, sample.pSample8 + selEnd, smpEnd - selEnd); - - // adjust loop points - AdjustLoopPoints(sample.nLoopStart, sample.nLoopEnd, sample.nLength); - AdjustLoopPoints(sample.nSustainStart, sample.nSustainEnd, sample.nLength); - - if(sample.nLoopEnd == 0) - { - sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP); - } - - if(sample.nSustainEnd == 0) - { - sample.uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); - } - - sample.PrecomputeLoops(sndFile); + ctrlSmp::RemoveRange(sample, m_dwBeginSel, m_dwEndSel, sndFile); } SetCurSel(0, 0); SetModified(updateHint, true, true); @@ -2103,6 +2084,8 @@ { // We want to store some loop metadata as well. memSize += sizeof(RIFFChunk) + sizeof(WAVSampleInfoChunk) + 2 * sizeof(WAVSampleLoop); + // ...and cue points, too. + memSize += sizeof(RIFFChunk) + sizeof(uint32_t) + CountOf(sample.cues) * sizeof(WAVCuePoint); } ASSERT((memSize % 2u) == 0); @@ -2138,6 +2121,7 @@ if(addLoopInfo) { file.WriteLoopInformation(sample); + file.WriteCueInformation(sample); } file.WriteExtraInformation(sample, sndFile.GetType(), sndFile.GetSampleName(m_nSample)); @@ -2729,6 +2713,23 @@ } +void CViewSample::OnSetCuePoint(UINT nID) +//--------------------------------------- +{ + nID -= ID_SAMPLE_CUE_1; + CModDoc *pModDoc = GetDocument(); + if (pModDoc) + { + CSoundFile &sndFile = pModDoc->GetrSoundFile(); + ModSample &sample = sndFile.GetSample(m_nSample); + + pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_none, "Set Cue Point"); + sample.cues[nID] = m_dwMenuParam; + SetModified(SampleHint().Info().Data(), true, false); + } +} + + void CViewSample::OnZoomUp() //-------------------------- { @@ -3015,7 +3016,7 @@ if(noteChannel[note - NOTE_MIN] != CHANNELINDEX_INVALID) { // Release sustain loop on key up - pModDoc->GetrSoundFile().KeyOff(&GetDocument()->GetrSoundFile().m_PlayState.Chn[noteChannel[note - NOTE_MIN]]); + sndFile.KeyOff(&sndFile.m_PlayState.Chn[noteChannel[note - NOTE_MIN]]); } break; case seNoteOffOnKeyUp: @@ -3027,6 +3028,11 @@ } return wParam; } + } else if(wParam >= kcStartSampleCues && wParam <= kcEndSampleCues) + { + const ModSample &sample = sndFile.GetSample(m_nSample); + SmpLength offset = sample.cues[wParam - kcStartSampleCues]; + if(offset < sample.nLength) PlayNote(NOTE_MIDDLEC, offset); } // Pass on to ctrl_smp Modified: trunk/OpenMPT/mptrack/View_smp.h =================================================================== --- trunk/OpenMPT/mptrack/View_smp.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/View_smp.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -43,7 +43,7 @@ int m_nZoom; // < 0: Zoom into sample (2^x:1 ratio), 0: Auto zoom, > 0: Zoom out (1:2^x ratio) FlagSet<Flags> m_dwStatus; SmpLength m_dwBeginSel, m_dwEndSel, m_dwBeginDrag, m_dwEndDrag; - DWORD m_dwMenuParam; + SmpLength m_dwMenuParam; SmpLength m_nGridSegments; SAMPLEINDEX m_nSample; @@ -101,8 +101,6 @@ SmpLength ScrollPosToSamplePos() const {return ScrollPosToSamplePos(m_nZoom);} inline SmpLength ScrollPosToSamplePos(int nZoom) const; - void AdjustLoopPoints(SmpLength &loopStart, SmpLength &loopEnd, SmpLength length) const; - void OnMonoConvert(ctrlSmp::StereoToMonoMode convert); public: @@ -162,6 +160,7 @@ afx_msg void OnSetLoopEnd(); afx_msg void OnSetSustainStart(); afx_msg void OnSetSustainEnd(); + afx_msg void OnSetCuePoint(UINT nID); afx_msg void OnZoomUp(); afx_msg void OnZoomDown(); afx_msg void OnDrawingToggle(); Modified: trunk/OpenMPT/mptrack/mptrack.rc =================================================================== --- trunk/OpenMPT/mptrack/mptrack.rc 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/mptrack.rc 2015-03-11 14:15:51 UTC (rev 4862) @@ -1318,7 +1318,7 @@ COMBOBOX IDC_COMBO2,114,18,149,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Volume Command:",IDC_STATIC,6,36,71,8 COMBOBOX IDC_COMBO3,6,48,102,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Value:",IDC_STATIC,114,36,150,8 + LTEXT "Value:",IDC_TEXT2,114,36,150,8 CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,114,48,150,12 LTEXT "Effect Type:",IDC_STATIC,6,66,55,8 COMBOBOX IDC_COMBO4,6,78,102,83,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP Modified: trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb =================================================================== --- trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb 2015-03-11 14:15:51 UTC (rev 4862) @@ -304,6 +304,15 @@ 8:1908:2:65:1 //Transpose -1 (Note Map): Ctrl+A (KeyDown) 8:1909:3:81:1 //Transpose +12 (Note Map): Shift+Ctrl+Q (KeyDown) 8:1910:3:65:1 //Transpose -12 (Note Map): Shift+Ctrl+A (KeyDown) +8:1924:1:49:1 //Preview Sample Cue 1: Shift+1 (KeyDown) +8:1925:1:50:1 //Preview Sample Cue 2: Shift+2 (KeyDown) +8:1926:1:51:1 //Preview Sample Cue 3: Shift+3 (KeyDown) +8:1927:1:52:1 //Preview Sample Cue 4: Shift+4 (KeyDown) +8:1928:1:53:1 //Preview Sample Cue 5: Shift+5 (KeyDown) +8:1929:1:54:1 //Preview Sample Cue 6: Shift+6 (KeyDown) +8:1930:1:55:1 //Preview Sample Cue 7: Shift+7 (KeyDown) +8:1931:1:56:1 //Preview Sample Cue 8: Shift+8 (KeyDown) +8:1932:1:57:1 //Preview Sample Cue 9: Shift+9 (KeyDown) //----( Instrument Context [bottom] (9) )------------ 9:1837:0:107:5 //Zoom In: NUM PLUS (KeyDown|KeyHold) Modified: trunk/OpenMPT/mptrack/resource.h =================================================================== --- trunk/OpenMPT/mptrack/resource.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/mptrack/resource.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -1092,7 +1092,6 @@ #define ID_MODTREE_SOLO 32898 #define ID_ESTIMATESONGLENGTH 32899 #define ID_PATTERN_VISUALIZE_EFFECT 32900 -#define ID_ACCELERATOR32900 32900 #define ID_PATTERN_PLAYNOLOOP 32901 #define ID_PATTERN_OPEN_RANDOMIZER 32905 #define ID_PATTERN_INTERPOLATE_NOTE 32906 @@ -1229,9 +1228,12 @@ #define ID_INTERNETUPDATE 44458 #define ID_HELP_EXAMPLEMODULES 44459 #define ID_FILE_SAVEASTEMPLATE 44460 -#define ID_ORDERLIST_INSERT_SEPARATOR 44461 -#define ID_ENVELOPE_LOAD 44462 -#define ID_ENVELOPE_SAVE 44463 +#define ID_SAMPLE_CUE_1 44461 +// From here: Command range [ID_SAMPLE_CUE_1, ID_SAMPLE_CUE_9] +#define ID_SAMPLE_CUE_9 44469 +#define ID_ORDERLIST_INSERT_SEPARATOR 44470 +#define ID_ENVELOPE_LOAD 44471 +#define ID_ENVELOPE_SAVE 44472 #define ID_PLUGINEDITOR_SLIDERS_BASE 44500 // From here: Command range [ID_PLUGINEDITOR_SLIDERS_BASE, ID_PLUGINEDITOR_SLIDERS_BASE + NUM_PLUGINEDITOR_PARAMETERS] #define ID_PLUGINEDITOR_EDIT_BASE 44550 Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -2078,6 +2078,27 @@ WRITEMODULAR('R','P','.','.', m_nRestartPos); } + // Sample cues + if(GetType() == MOD_TYPE_MPT) + { + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + { + const ModSample &sample = Samples[smp]; + if(sample.nLength && sample.HasCustomCuePoints()) + { + // Write one chunk for every sample. + // Rationale: chunks are limited to 65536 bytes, which can easily be reached + // with the amount of samples that OpenMPT supports. + WRITEMODULARHEADER('S','E','U','C', 2 + CountOf(sample.cues) * 4); + mpt::IO::WriteIntLE<uint16_t>(f, smp); + for(int i = 0; i < CountOf(sample.cues); i++) + { + mpt::IO::WriteIntLE<uint32_t>(f, sample.cues[i]); + } + } + } + } + //Additional flags for XM/IT/MPTM if(m_ModFlags) { @@ -2235,8 +2256,23 @@ } } } + break; - break; + case MAGIC4LE('C','U','E','S'): + // Sample cues + if(size > 2) + { + SAMPLEINDEX smp = chunk.ReadUint16LE(); + if(smp > 0 && smp <= GetNumSamples()) + { + ModSample &sample = Samples[smp]; + for(int i = 0; i < CountOf(sample.cues); i++) + { + sample.cues[i] = chunk.ReadUint32LE(); + } + } + } + break; } } Modified: trunk/OpenMPT/soundlib/Load_mt2.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mt2.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/Load_mt2.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -341,7 +341,7 @@ m.param = p.fxparam1; that->ConvertModCommand(m); #ifdef MODPLUG_TRACKER - m.Convert(MOD_TYPE_XM, MOD_TYPE_IT); + m.Convert(MOD_TYPE_XM, MOD_TYPE_IT, *that); #endif // MODPLUG_TRACKER } else { Modified: trunk/OpenMPT/soundlib/Load_mtm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mtm.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/Load_mtm.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -186,7 +186,7 @@ if(cmd != 0 || param != 0) { ConvertModCommand(*m); - m->Convert(MOD_TYPE_MOD, MOD_TYPE_S3M); + m->Convert(MOD_TYPE_MOD, MOD_TYPE_S3M, *this); } } } Modified: trunk/OpenMPT/soundlib/ModChannel.h =================================================================== --- trunk/OpenMPT/soundlib/ModChannel.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/ModChannel.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -62,6 +62,7 @@ // Information not used in the mixer const ModInstrument *pModInstrument; // Currently assigned instrument slot SmpLength proTrackerOffset; // Offset for instrument-less notes in ProTracker mode + SmpLength oldOffset; FlagSet<ChannelFlags> dwOldFlags; // Flags from previous tick int32 newLeftVol, newRightVol; int32 nRealVolume, nRealPan; @@ -83,10 +84,11 @@ int32 nRetrigCount, nRetrigParam; ROWINDEX nPatternLoop; CHANNELINDEX nMasterChn; + ModCommand rowCommand; // 8-bit members uint8 resamplingMode; - uint8 nRestoreResonanceOnNewNote; //Like above - uint8 nRestoreCutoffOnNewNote; //Like above + uint8 nRestoreResonanceOnNewNote; // See nRestorePanOnNewNote + uint8 nRestoreCutoffOnNewNote; // ditto uint8 nNote, nNNA; uint8 nLastNote; // Last note, ignoring note offs and cuts - for MIDI macros uint8 nArpeggioLastNote, nArpeggioBaseNote; // For plugin arpeggio @@ -99,7 +101,7 @@ uint8 nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth; int8 nPanbrelloOffset, nPanbrelloRandomMemory; uint8 nOldCmdEx, nOldVolParam, nOldTempo; - uint8 nOldOffset, nOldHiOffset; + uint8 nOldHiOffset; uint8 nCutOff, nResonance; uint8 nTremorCount, nTremorParam; uint8 nPatternLoopCount; @@ -108,30 +110,28 @@ uint8 nEFxSpeed, nEFxDelay; // memory for Invert Loop (EFx, .MOD only) uint8 nNoteSlideCounter, nNoteSlideSpeed, nNoteSlideStep; // IMF / PTM Note Slide uint8 lastZxxParam; // Memory for \xx slides - bool isFirstTick; + bool isFirstTick : 1; - ModCommand rowCommand; + //-->Variables used to make user-definable tuning modes work with pattern effects. + //If true, freq should be recalculated in ReadNote() on first tick. + //Currently used only for vibrato things - using in other context might be + //problematic. + bool m_ReCalculateFreqOnFirstTick : 1; - //NOTE_PCs memory. - float m_plugParamValueStep, m_plugParamTargetValue; - uint16 m_RowPlugParam; - PLUGINDEX m_RowPlug; + //To tell whether to calculate frequency. + bool m_CalculateFreq : 1; - //-->Variables used to make user-definable tuning modes work with pattern effects. int32 m_PortamentoFineSteps, m_PortamentoTickSlide; uint32 m_Freq; float m_VibratoDepth; + //<---- - //If true, freq should be recalculated in ReadNote() on first tick. - //Currently used only for vibrato things - using in other context might be - //problematic. - bool m_ReCalculateFreqOnFirstTick; + //NOTE_PCs memory. + float m_plugParamValueStep, m_plugParamTargetValue; + uint16 m_RowPlugParam; + PLUGINDEX m_RowPlug; - //To tell whether to calculate frequency. - bool m_CalculateFreq; - //<---- - void ClearRowCmd() { rowCommand = ModCommand::Empty(); } // Get a reference to a specific envelope of this channel Modified: trunk/OpenMPT/soundlib/ModSample.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSample.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/ModSample.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -126,6 +126,12 @@ nVibDepth = 0; nVibRate = 0; filename[0] = '\0'; + + // Default cues compatible with old-style volume column offset + for(int i = 0; i < 9; i++) + { + cues[i] = (i + 1) << 11; + } } @@ -339,4 +345,16 @@ } +// Check if the sample's cue points are the default cue point set. +bool ModSample::HasCustomCuePoints() const +//---------------------------------------- +{ + for(SmpLength i = 0; i < CountOf(cues); i++) + { + if(cues[i] != (i + 1) << 11) return true; + } + return false; +} + + OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/soundlib/ModSample.h =================================================================== --- trunk/OpenMPT/soundlib/ModSample.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/ModSample.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -39,6 +39,7 @@ 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, the current structure size is 64 Bytes - would adding the sample name here slow down the mixer (cache misses)? char filename [MAX_SAMPLEFILENAME]; + SmpLength cues[9]; ModSample(MODTYPE type = MOD_TYPE_NONE) { @@ -96,6 +97,9 @@ void TransposeToFrequency(); static int FrequencyToTranspose(uint32 freq); void FrequencyToTranspose(); + + // Check if the sample's cue points are the default cue point set. + bool HasCustomCuePoints() const; }; OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -490,6 +490,10 @@ file.WriteLoopInformation(sample); file.WriteExtraInformation(sample, GetType()); + if(sample.HasCustomCuePoints()) + { + file.WriteCueInformation(sample); + } FileTags tags; tags.title = mpt::ToUnicode(mpt::CharsetLocale, m_szNames[nSample]); @@ -2193,11 +2197,12 @@ FLAC__StreamMetadata *metadata[] = { FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), - FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), - FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), + FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), // MPT sample information + FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), // Loop points + FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), // Cue points }; - const bool writeLoopData = sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP]; + unsigned numBlocks = 2; if(metadata[0]) { // Store sample name @@ -2229,10 +2234,10 @@ FLAC__metadata_object_application_set_data(metadata[1], reinterpret_cast<FLAC__byte *>(&chunk), length, true); } - if(metadata[2] && writeLoopData) + if(metadata[numBlocks] && sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP]) { // Store loop points - memcpy(metadata[2]->data.application.id, "riff", 4); + memcpy(metadata[numBlocks]->data.application.id, "riff", 4); struct { @@ -2263,14 +2268,42 @@ chunk.loops[0].ConvertEndianness(); chunk.loops[1].ConvertEndianness(); - FLAC__metadata_object_application_set_data(metadata[2], reinterpret_cast<FLAC__byte *>(&chunk), length, true); + FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true); + numBlocks++; } + if(metadata[numBlocks] && sample.HasCustomCuePoints()) + { + // Store cue points + memcpy(metadata[numBlocks]->data.application.id, "riff", 4); + struct + { + RIFFChunk header; + uint32_t numPoints; + WAVCuePoint cues[CountOf(sample.cues)]; + } chunk; + + chunk.header.id = RIFFChunk::idcue_; + chunk.header.length = 4 + sizeof(chunk.cues); + + for(uint32_t i = 0; i < CountOf(sample.cues); i++) + { + chunk.cues[i].ConvertToWAV(i, sample.cues[i]); + chunk.cues[i].ConvertEndianness(); + } + + const uint32_t length = sizeof(RIFFChunk) + chunk.header.length; + chunk.header.ConvertEndianness(); + + FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true); + numBlocks++; + } + FLAC__stream_encoder_set_channels(encoder, sample.GetNumChannels()); FLAC__stream_encoder_set_bits_per_sample(encoder, sample.GetElementarySampleSize() * 8); FLAC__stream_encoder_set_sample_rate(encoder, sample.GetSampleRate(GetType())); FLAC__stream_encoder_set_total_samples_estimate(encoder, sample.nLength); - FLAC__stream_encoder_set_metadata(encoder, metadata, writeLoopData ? 3 : 2); + FLAC__stream_encoder_set_metadata(encoder, metadata, numBlocks); #ifdef MODPLUG_TRACKER FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel); #endif // MODPLUG_TRACKER Modified: trunk/OpenMPT/soundlib/Snd_defs.h =================================================================== --- trunk/OpenMPT/soundlib/Snd_defs.h 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/Snd_defs.h 2015-03-11 14:15:51 UTC (rev 4862) @@ -166,7 +166,7 @@ #define CHN_SAMPLEFLAGS (CHN_16BIT | CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN | CHN_PANNING | CHN_STEREO | CHN_PINGPONGFLAG | CHN_REVERSE) #define CHN_CHANNELFLAGS (~CHN_SAMPLEFLAGS) -// Sample flags fit into the first 16 bits, and with the current memory layout, storing them as a 16-bit integer gives struct ModSample a nice cacheable 64 bytes size in 32-bit builds. +// Sample flags fit into the first 16 bits, and with the current memory layout, storing them as a 16-bit integer packs struct ModSample nicely. typedef FlagSet<ChannelFlags, uint16> SampleFlags; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2015-03-11 12:55:36 UTC (rev 4861) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2015-03-11 14:15:51 UTC (rev 4862) @@ -112,10 +112,6 @@ const bool hasSearchTarget = target.mode != GetLengthTarget::NoTarget; const bool adjustSamplePos = (adjustMode & eAdjustSamplePositions) == eAdjustSamplePositions; - ROWINDEX nRow = target.startRow, nNextRow = nRow; - ROWINDEX nNextPatStartRow = 0; // FT2 E60 bug - ORDERINDEX nCurrentOrder = target.startOrder, nNextOrder = nCurrentOrder; - SEQUENCEINDEX sequence = target.sequence; if(sequence > Order.GetNumSequences()) sequence = Order.GetCurrentSequenceIndex(); const ModSequence &orderList = Order.GetSequence(sequence); @@ -124,6 +120,9 @@ // 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, sequence); + memory.state.m_nNextRow = memory.state.m_nRow = target.startRow; + memory.state.m_nNextOrder = memory.state.m_nCurrentOrder = target.startOrder; + // Optimize away channels for which it's pointless to adjust sample positions std::vector<bool> adjustSampleChn(GetNumChannels(), true); if(adjustSamplePos && target.mode == GetLengthTarget::SeekPosition) @@ -178,43 +177,43 @@ } uint32 rowDelay = 0, tickDelay = 0; - nRow = nNextRow; - nCurrentOrder = nNextOrder; + memory.state.m_nRow = memory.state.m_nNextRow; + memory.state.m_nCurrentOrder = memory.state.m_nNextOrder; - if(nCurrentOrder >= orderList.size()) + if(memory.state.m_nCurrentOrder >= orderList.size()) break; // Check if pattern is valid - PATTERNINDEX nPattern = orderList[nCurrentOrder]; + memory.state.m_nPattern = orderList[memory.state.m_nCurrentOrder]; bool positionJumpOnThisRow = false; bool patternBreakOnThisRow = false; bool patternLoopEndedOnThisRow = false, patternLoopStartedOnThisRow = false; - if(nPattern == orderList.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && nCurrentOrder == target.pos.order) + if(memory.state.m_nPattern == orderList.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && memory.state.m_nCurrentOrder == target.pos.order) { // Early test: Target is inside +++ pattern retval.targetReached = true; break; } - while(nPattern >= Patterns.Size()) + while(memory.state.m_nPattern >= Patterns.Size()) { // End of song? - if((nPattern == orderList.GetInvalidPatIndex()) || (nCurrentOrder >= orderList.size())) + if((memory.state.m_nPattern == orderList.GetInvalidPatIndex()) || (memory.state.m_nCurrentOrder >= orderList.size())) { - if(nCurrentOrder == m_nRestartPos) + if(memory.state.m_nCurrentOrder == m_nRestartPos) break; else - nCurrentOrder = m_nRestartPos; + memory.state.m_nCurrentOrder = m_nRestartPos; } else { - nCurrentOrder++; + memory.state.m_nCurrentOrder++; } - nPattern = (nCurrentOrder < orderList.size()) ? orderList[nCurrentOrder] : orderList.GetInvalidPatIndex(); - nNextOrder = nCurrentOrder; - if((!Patterns.IsValidPat(nPattern)) && visitedRows.IsVisited(nCurrentOrder, 0, true)) + memory.state.m_nPattern = (memory.state.m_nCurrentOrder < orderList.size()) ? orderList[memory.state.m_nCurrentOrder] : orderList.GetInvalidPatIndex(); + memory.state.m_nNextOrder = memory.state.m_nCurrentOrder; + if((!Patterns.IsValidPat(memory.state.m_nPattern)) && visitedRows.IsVisited(memory.state.m_nCurrentOrder, 0, true)) { - if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(nNextOrder, nNextRow, true)) + if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(memory.state.m_nNextOrder, memory.state.m_nNextRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; @@ -223,24 +222,24 @@ // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. retval.duration = memory.elapsedTime; results.push_back(retval); - retval.startRow = nNextRow; - retval.startOrder = nNextOrder; + retval.startRow = memory.state.m_nNextRow; + retval.startOrder = memory.state.m_nNextOrder; memory.Reset(); - nRow = nNextRow; - nCurrentOrder = nNextOrder; - nPattern = orderList[nCurrentOrder]; + memory.state.m_nRow = memory.state.m_nNextRow; + memory.state.m_nCurrentOrder = memory.state.m_nNextOrder; + memory.state.m_nPattern = orderList[memory.state.m_nCurrentOrder]; break; } } } // Skip non-existing patterns - if((nPattern >= Patterns.Size()) || (!Patterns[nPattern])) + if((memory.state.m_nPattern >= Patterns.Size()) || (!Patterns[memory.state.m_nPattern])) { // If there isn't even a tune, we should probably stop here. - if(nCurrentOrder == m_nRestartPos) + if(memory.state.m_nCurrentOrder == m_nRestartPos) { - if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(nNextOrder, nNextRow, true)) + if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(memory.state.m_nNextOrder, memory.state.m_nNextRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; @@ -249,29 +248,29 @@ // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. retval.duration = memory.elapsedTime; results.push_back(retval); - retval.startRow = nNextRow; - retval.startOrder = nNextOrder; + retval.startRow = memory.state.m_nNextRow; + retval.startOrder = memory.state.m_nNextOrder; memory.Reset(); continue; } } - nNextOrder = nCurrentOrder + 1; + memory.state.m_nNextOrder = memory.state.m_nCurrentOrder + 1; continue; } // Should never happen - if(nRow >= Patterns[nPattern].GetNumRows()) - nRow = 0; + if(memory.state.m_nRow >= Patterns[memory.state.m_nPattern].GetNumRows()) + memory.state.m_nRow = 0; // Check whether target was reached. - if(target.mode == GetLengthTarget::SeekPosition && nCurrentOrder == target.pos.order && nRow == target.pos.row) + if(target.mode == GetLengthTarget::SeekPosition && memory.state.m_nCurrentOrder == target.pos.order && memory.state.m_nRow == target.pos.row) { retval.targetReached = true; break; } - if(visitedRows.IsVisited(nCurrentOrder, nRow, true)) + if(visitedRows.IsVisited(memory.state.m_nCurrentOrder, memory.state.m_nRow, true)) { - if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(nNextOrder, nNextRow, true)) + if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(memory.state.m_nNextOrder, memory.state.m_nNextRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; @@ -280,28 +279,27 @@ // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. retval.duration = memory.elapsedTime; results.push_back(retval); - retval.startRow = nNextRow; - retval.startOrder = nNextOrder; + retval.startRow = memory.state.m_nNextRow; + retval.startOrder = memory.state.m_nNextOrder; memory.Reset(); continue; } } - retval.endOrder = nCurrentOrder; - retval.endRow = nRow; + retval.endOrder = memory.state.m_nCurrentOrder; + retval.endRow = memory.state.m_nRow; // Update next position - nNextRow = nRow + 1; + memory.state.m_nNextRow = memory.state.m_nRow + 1; - if(!nRow) + if(!memory.state.m_nRow) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) memory.chnSettings[chn].patLoop = memory.elapsedTime; } ModChannel *pChn = memory.state.Chn; - ModCommand *p = Patterns[nPattern].GetRow(nRow); - ModCommand *nextRow = nullptr; + ModCommand *p = Patterns[memory.state.m_nPattern].GetRow(memory.state.m_nRow); for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); p++, pChn++, nChn++) if(!p->IsEmpty()) { if(IsCompatibleMode(TRK_SCREAMTRACKER) && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels @@ -322,12 +320,12 @@ // Position Jump case CMD_POSITIONJUMP: positionJumpOnThisRow = true; - nNextOrder = (ORDERINDEX)param; - nNextPatStartRow = 0; // FT2 E60 bug + memory.state.m_nNextOrder = (ORDERINDEX)param; + memory.state.m_nNextPatStartRow = 0; // FT2 E60 bug // see http://forum.openmpt.org/index.php?topic=2769.0 - FastTracker resets Dxx if Bxx is called _after_ Dxx // Test case: PatternJump.mod if(!patternBreakOnThisRow || (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) - nNextRow = 0; + memory.state.m_nNextRow = 0; if ((adjustMode & eAdjust)) { @@ -337,36 +335,24 @@ break; // Pattern Break case CMD_PATTERNBREAK: - if(param >= 64 && (GetType() & MOD_TYPE_S3M)) { - // ST3 ignores invalid pattern breaks. - break; - } - patternBreakOnThisRow = true; - //Try to check next row for XPARAM - nextRow = nullptr; - nNextPatStartRow = 0; // FT2 E60 bug - if (nRow < Patterns[nPattern].GetNumRows() - 1) - { - nextRow = Patterns[nPattern].GetpModCommand(nRow + 1, nChn); - } - if (nextRow && nextRow->command == CMD_XPARAM) - { - nNextRow = (param << 8) + nextRow->param; - } else - { - nNextRow = param; - } + ROWINDEX row = PatternBreak(memory.state, nChn, param); + if(row != ROWINDEX_INVALID) + { + patternBreakOnThisRow = true; + memory.state.m_nNextRow = row; - if (!positionJumpOnThisRow) - { - nNextOrder = nCurrentOrder + 1; + if(!positionJumpOnThisRow) + { + memory.state.m_nNextOrder = memory.state.m_nCurrentOrder + 1; + } + if(adjustMode & eAdjust) + { + pChn->nPatternLoopCount = 0; + pChn->nPatternLoop = 0; + } + } } - if ((adjustMode & eAdjust)) - { - pChn->nPatternLoopCount = 0; - pChn->nPatternLoop = 0; - } break; // Set Speed case CMD_SPEED: @@ -456,7 +442,7 @@ for(CHANNELINDEX c = firstChn; c <= lastChn; c++) { memory.chnSettings[c].patLoop = memory.elapsedTime; - memory.chnSettings[c].patLoopStart = nRow; + memory.chnSettings[c].patLoopStart = memory.state.m_nRow; } patternLoopStartedOnThisRow = true; } @@ -473,13 +459,13 @@ // Pattern Loop if (param & 0x0F) { - nNextPatStartRow = memory.chnSettings[nChn].patLoopStart; // FT2 E60 bug + memory.state.m_nNextPatStartRow = memory.chnSettings[nChn].patLoopStart; // FT2 E60 bug patternLoopEndedOnThisRow = true; } else { patternLoopStartedOnThisRow = true; memory.chnSettings[nChn].patLoop = memory.elapsedTime; - memory.chnSettings[nChn].patLoopStart = nRow; + memory.chnSettings[nChn].patLoopStart = memory.state.m_nRow; } } break; @@ -489,6 +475,8 @@ if(((param & 0xF0) == 0xA0) && !IsCompatibleMode(TRK_FASTTRACKER2)) pChn->nOldHiOffset = param & 0x0F; break; } + + // The following calculations are not interesting if we just want to get the song length. if ((adjustMode & eAdjust) == 0) continue; switch(command) { @@ -503,7 +491,7 @@ break; // Offset case CMD_OFFSET: - if (param) pChn->nOldOffset = param; + if (param) pChn->oldOffset = param << 8; break; // Volume Slide case CMD_VOLUMESLIDE: @@ -594,12 +582,12 @@ } } - if(nNextRow >= Patterns[nPattern].GetNumRows()) + if(memory.state.m_nNextRow >= Patterns[memory.state.m_nPattern].GetNumRows()) { - nNextOrder = nCurrentOrder + 1; - nNextRow = 0; - if(IsCompatibleMode(TRK_FASTTRACKER2)) nNextRow = nNextPatStartRow; // FT2 E60 bug - nNextPatStartRow = 0; + memory.state.m_nNextOrder = memory.state.m_nCurrentOrder + 1; + memory.state.m_nNextRow = 0; + if(IsCompatibleMode(TRK_FASTTRACKER2)) memory.state.m_nNextRow = memory.state.m_nNextPatStartRow; // FT2 E60 bug + memory.state.m_nNextPatStartRow = 0; } // Interpret F00 effect in XM files as "stop song" @@ -609,9 +597,9 @@ } ROWINDEX rowsPerBeat = m_nDefaultRowsPerBeat; - if(Patterns[nPattern].GetOverrideSignature()) + if(Patterns[memory.state.m_nPattern].GetOverrideSignature()) { - rowsPerBeat = Patterns[nPattern].GetRowsPerBeat(); + rowsPerBeat = Patterns[memory.state.m_nPattern].GetRowsPerBeat(); } const uint32 tickDuration = GetTickDuration(memory.state.m_nMusicTempo, memory.state.m_nMusicSpeed, rowsPerBeat); @@ -624,7 +612,7 @@ { // Super experimental and dirty sample seeking pChn = memory.state.Chn; - p = Patterns[nPattern].GetRow(nRow); + p = Patterns[memory.state.m_nPattern].GetRow(memory.state.m_nRow); for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); p++, pChn++, nChn++) { if(!adjustSampleChn[nChn]) @@ -650,17 +638,30 @@ { startTick = paramHi; } + + if(p->command == CMD_OFFSET) + { + SmpLength offset = CalculateXParam(memory.state.m_nPattern, memory.state.m_nRow, nChn); + if(offset < 256) + { + offset <<= 8; + if(offset == 0) offset = pChn->oldOffset; + offset += static_cast<SmpLength>(pChn->nOldHiOffset) << 16; + } + SampleOffset(nChn, offset); + } else if(p->volcmd == VOLCMD_OFFSET) + { + if(p->vol <= CountOf(pChn->pModSample->cues) && pChn->pModSample != nullptr) + { + SmpLength offset; + if(p->vol == 0) + offset = pChn->oldOffset; + else + offset = pChn->oldOffset = pChn->pModSample->cues[p->vol - 1]; + SampleOffset(nChn, offset); + } + } } - if(p->command == CMD_OFFSET) - { - // TODO: xParam not supported! (Note: xParam doesn't use hiOffset) - if(p->param != 0) pChn->nOldOffset = p->param; - if(p->IsNote()) pChn->nPos = (pChn->nOldHiOffset << 16) + (pChn->nOldOffset << 8); - } else if(p->volcmd == VOLCMD_OFFSET) - { - if(p->vol != 0) pChn->nOldOffset = p->vol << 3; - if(p->IsNote()) pChn->nPos = (pChn->nOldHiOffset << 16) + (pChn->nOldOffset << 8); - } if(p->note == NOTE_KEYOFF || p->note == NOTE_NOTECUT || (p->note == NOTE_FADE && GetNumInstruments()) || ((p->command == CMD_MODCMDEX || p->command == CMD_S3MCMDEX) && (p->param & 0xF0) == 0xC0 && paramLo < numTicks) @@ -800,7 +801,7 @@ if(patternLoopEndedOnThisRow) { - p = Patterns[nPattern].GetRow(nRow); + p = Patterns[memory.state.m_nPattern].GetRow(memory.state.m_nRow); std::map<double, int> startTimes; // This is really just a simple estimation for nested pattern loops. It should handle cases correctly where all parallel loops start and end on the same row. // If one of them starts or ends "in between", it will most likely calculate a wrong duration. @@ -822,7 +823,7 @@ if(GetType() == MOD_TYPE_IT) { // IT pattern loop start row update - at the end of a pattern loop, set pattern loop start to next row (for upcoming pattern loops with missing SB0) - p = Patterns[nPattern].GetRow(nRow); + p = Patterns[memory.state.m_nPattern].GetRow(memory.state.m_nRow); for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); p++, nChn++) { if((p->command == CMD_S3MCMDEX && p->param >= 0xB1 && p->param <= 0xBF)) @@ -836,14 +837,14 @@ if(retval.targetReached || target.mode == GetLengthTarget::NoTarget) { - retval.lastOrder = nCurrentOrder; - retval.lastRow = nRow; + retval.lastOrder = memory.state.m_nCurrentOrder; + retval.lastRow = memory.state.m_nRow; } retval.duration = memory.elapsedTime; results.push_back(retval); // Store final variables - if((adjustMode & eAdjust)) + if(adjustMode & eAdjust) { if(retval.targetReached || target.mode == GetLengthTarget::NoTarget) { @@ -856,12 +857,7 @@ if(memory.state.Chn[n].nLastNote != NOTE_NONE) { m_PlayState.Chn[n].nNewNote = memory.state.Chn[n].nLastNote; - if(ModCommand::IsNote(memory.state.Chn[n].nLastNote)) - { - m_PlayState.Chn[n].nLastNote = memory.state.Chn[n].nLastNote; - } } - if(memory.state.Chn[n].nNewIns) m_PlayState.Chn[n].nNewIns = memory.state.Chn[n].nNewIns; if(memory.chnSettings[n].vol != 0xFF) { ... [truncated message content] |