From: <sv...@op...> - 2024-11-04 17:38:52
|
Author: sagamusix Date: Mon Nov 4 18:38:39 2024 New Revision: 22093 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=22093 Log: [Mod] Change NOTE_MAX so that there are 128 valid notes instead of 120, like in the instrument keyboard mapping. Fixes bad notes in some Future Composer files (https://www.un4seen.com/forum/?topic=15448.msg144041#msg144041). [Var] Update MPTM/XM tests to verify correct writing of special notes and notes at the upper/lower note limit. Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/soundlib/InstrumentSynth.cpp trunk/OpenMPT/soundlib/Load_fc.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/mod_specifications.cpp trunk/OpenMPT/soundlib/modcommand.h trunk/OpenMPT/test/test.cpp trunk/OpenMPT/test/test.mptm trunk/OpenMPT/test/test.xm Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -175,6 +175,13 @@ dc.IntersectClipRect(&rcClient); const CSoundFile &sndFile = m_modDoc.GetSoundFile(); + const auto &modSpecs = sndFile.GetModSpecifications(); + int noteMin = 0, noteMax = NOTE_MAX - NOTE_MIN; + if(modSpecs.instrumentsMax) + { + noteMin = modSpecs.noteMin - NOTE_MIN; + noteMax = modSpecs.noteMax - NOTE_MIN; + } if (m_cxFont > 0 && m_cyFont > 0) { const bool focus = (::GetFocus() == m_hWnd); @@ -185,11 +192,11 @@ int nPos = m_nNote - (nNotes/2); int ypaint = 0; mpt::winstring s; - for (int ynote=0; ynote<nNotes; ynote++, ypaint+=m_cyFont, nPos++) + for(int ynote = 0; ynote < nNotes; ynote++, ypaint += m_cyFont, nPos++) { // Note - bool isValidPos = (nPos >= 0) && (nPos < NOTE_MAX - NOTE_MIN + 1); - if (isValidPos) + const bool isValidPos = mpt::is_in_range(nPos, noteMin, noteMax); + if(isValidPos) { s = mpt::ToWin(sndFile.GetNoteName(static_cast<ModCommand::NOTE>(nPos + 1), m_nInstrument)); s.resize(4); @@ -230,7 +237,7 @@ rect.left = rcClient.left + m_cxFont * 2 + 3; rect.right = rcClient.right; s = _T(" .."); - if(pIns && nPos >= 0 && nPos < NOTE_MAX && pIns->Keyboard[nPos]) + if(pIns && isValidPos && pIns->Keyboard[nPos]) { s = mpt::tfmt::right(3, mpt::tfmt::dec(pIns->Keyboard[nPos])); } @@ -755,40 +762,48 @@ bool redraw = false; //HACK: handle numpad (convert numpad number key to normal number key) - if ((k >= VK_NUMPAD0) && (k <= VK_NUMPAD9)) return HandleChar(k-VK_NUMPAD0+'0'); + if ((k >= VK_NUMPAD0) && (k <= VK_NUMPAD9)) + return HandleChar(k-VK_NUMPAD0+'0'); + + const CSoundFile &sndFile = m_modDoc.GetSoundFile(); + const auto &modSpecs = sndFile.GetModSpecifications(); + UINT noteMin = 0, noteMax = NOTE_MAX - NOTE_MIN; + if(modSpecs.instrumentsMax) + { + noteMin = modSpecs.noteMin - NOTE_MIN; + noteMax = modSpecs.noteMax - NOTE_MIN; + } switch(k) { case VK_RIGHT: - if (!m_bIns) { m_bIns = true; redraw = true; } else - if (m_nNote < NOTE_MAX - NOTE_MIN) { m_nNote++; m_bIns = false; redraw = true; } + if (!m_bIns) { m_bIns = true; redraw = true; } + else if (m_nNote < noteMax) { m_nNote++; m_bIns = false; redraw = true; } break; case VK_LEFT: - if (m_bIns) { m_bIns = false; redraw = true; } else - if (m_nNote) { m_nNote--; m_bIns = true; redraw = true; } + if (m_bIns) { m_bIns = false; redraw = true; } + else if (m_nNote > noteMin) { m_nNote--; m_bIns = true; redraw = true; } break; case VK_UP: - if (m_nNote > 0) { m_nNote--; redraw = true; } + if (m_nNote > noteMin) { m_nNote--; redraw = true; } break; case VK_DOWN: - if (m_nNote < NOTE_MAX - 1) { m_nNote++; redraw = true; } + if (m_nNote < noteMax) { m_nNote++; redraw = true; } break; case VK_PRIOR: - if (m_nNote > 3) { m_nNote -= 3; redraw = true; } else - if (m_nNote > 0) { m_nNote = 0; redraw = true; } + if (m_nNote > noteMin + 3) { m_nNote -= 3; redraw = true; } + else if (m_nNote > noteMin) { m_nNote = noteMin; redraw = true; } break; case VK_NEXT: - if (m_nNote+3 < NOTE_MAX) { m_nNote += 3; redraw = true; } else - if (m_nNote < NOTE_MAX - NOTE_MIN) { m_nNote = NOTE_MAX - NOTE_MIN; redraw = true; } + if (m_nNote + 3 < noteMax) { m_nNote += 3; redraw = true; } + else if (m_nNote < noteMax) { m_nNote = noteMax; redraw = true; } break; case VK_HOME: - if(m_nNote > 0) { m_nNote = 0; redraw = true; } + if(m_nNote > noteMin) { m_nNote = noteMin; redraw = true; } break; case VK_END: - if(m_nNote < NOTE_MAX - NOTE_MIN) { m_nNote = NOTE_MAX - NOTE_MIN; redraw = true; } + if(m_nNote < noteMax) { m_nNote = noteMax; redraw = true; } break; -// case VK_TAB: -// return true; case VK_RETURN: { ModInstrument *pIns = m_modDoc.GetSoundFile().Instruments[m_nInstrument]; Modified: trunk/OpenMPT/soundlib/InstrumentSynth.cpp ============================================================================== --- trunk/OpenMPT/soundlib/InstrumentSynth.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/InstrumentSynth.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -493,7 +493,7 @@ { uint8 fcNote = static_cast<uint8>(m_fcPitch >= 0 ? m_fcPitch + chn.nLastNote - NOTE_MIN : m_fcPitch) & 0x7F; static_assert(mpt::array_size<decltype(chn.pModInstrument->NoteMap)>::size > 0x7F); - if(m_fcPitch) + if(m_fcPitch && ModCommand::IsNote(chn.nLastNote)) period += (sndFile.GetPeriodFromNote(chn.pModInstrument->NoteMap[fcNote], chn.nFineTune, chn.nC5Speed) - sndFile.GetPeriodFromNote(chn.pModInstrument->NoteMap[chn.nLastNote - NOTE_MIN], chn.nFineTune, chn.nC5Speed)); if(doVibratoFC) Modified: trunk/OpenMPT/soundlib/Load_fc.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_fc.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/Load_fc.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -423,6 +423,7 @@ if(!instr) return false; + static_assert(NOTE_MAX - NOTE_MIN + 1 >= 128, "Need at least a note range of 128 for correct emulation of note wrap-around logic in Future Composer"); for(uint8 note = 0; note < static_cast<uint8>(instr->NoteMap.size()); note++) { if(note < 48) Modified: trunk/OpenMPT/soundlib/Load_it.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/Load_it.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -1098,11 +1098,14 @@ uint8 note = patternData.ReadUint8(); if(note < 0x80) note += NOTE_MIN; - if(!(GetType() & MOD_TYPE_MPT)) - { - if(note > NOTE_MAX && note < 0xFD) note = NOTE_FADE; - else if(note == 0xFD) note = NOTE_NONE; - } + else if(note == 0xFF) + note = NOTE_KEYOFF; + else if(note == 0xFE) + note = NOTE_NOTECUT; + else if(note == 0xFD && GetType() != MOD_TYPE_MPT) + note = NOTE_NONE; // Note: in MPTM format, NOTE_FADE is written as 0xFD to preserve compatibility with older OpenMPT versions. + else + note = NOTE_FADE; m.note = lastValue[ch].note = note; } if(chnMask[ch] & 2) @@ -1769,14 +1772,23 @@ } auto &chnState = chnStates[ch]; - uint8 b = 0; + uint8 b = 1; uint8 vol = 0xFF; uint8 note = m->note; - if (note != NOTE_NONE) b |= 1; - if (m->IsNote()) note -= NOTE_MIN; - if (note == NOTE_FADE && GetType() != MOD_TYPE_MPT) note = 0xF6; - if (m->instr) b |= 2; - if (m->volcmd != VOLCMD_NONE) + if(note >= NOTE_MIN && note <= NOTE_MIN + 119) + note = m->note - NOTE_MIN; + else if(note == NOTE_FADE) + note = (GetType() == MOD_TYPE_MPT) ? 0xFD : 0xF6; + else if(note == NOTE_NOTECUT) + note = 0xFE; + else if(note == NOTE_KEYOFF) + note = 0xFF; + else + b = 0; + + if(m->instr) + b |= 2; + if(m->volcmd != VOLCMD_NONE) { vol = std::min(m->vol, uint8(9)); switch(m->volcmd) @@ -1801,7 +1813,8 @@ default: vol = 0xFF; } } - if (vol != 0xFF) b |= 4; + if(vol != 0xFF) + b |= 4; uint8 command = 0, param = 0; if(m->command == CMD_VOLUME && vol == 0xFF) { Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -969,22 +969,23 @@ { info |= s3mNotePresent; - if(note == NOTE_NONE) - { - note = s3mNoteNone; - } else if(ModCommand::IsSpecialNote(note)) + if(ModCommand::IsSpecialNote(note)) { // Note Cut note = s3mNoteOff; - } else if(note < 12 + NOTE_MIN) + } else if(note < NOTE_MIN + 12) { // Too low note = 0; - } else if(note <= NOTE_MAX) + } else if(note <= NOTE_MIN + 107) { note -= (12 + NOTE_MIN); note = static_cast<uint8>((note % 12) + ((note / 12) << 4)); } + else + { + note = s3mNoteNone; + } if(m.instr > 0 && m.instr <= GetNumSamples()) { Modified: trunk/OpenMPT/soundlib/Load_xm.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/Load_xm.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -1262,9 +1262,12 @@ uint8 note = p->note, command = 0, param = 0; ModSaveCommand(*p, command, param, true, compatibilityExport); - if (note >= NOTE_MIN_SPECIAL) note = 97; else - if ((note <= 12) || (note > 96+12)) note = 0; else - note -= 12; + if(note >= NOTE_MIN_SPECIAL) + note = 97; + else if(note < NOTE_MIN + 12 || note >= NOTE_MIN + 12 + 96) + note = 0; + else + note -= 12; uint8 vol = 0; if (p->volcmd != VOLCMD_NONE) { Modified: trunk/OpenMPT/soundlib/Sndfile.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/Sndfile.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -1643,9 +1643,10 @@ return specialNoteNames[note - NOTE_MIN_SPECIAL]; } else if(ModCommand::IsNote(note)) { + const int octave = (note - NOTE_MIN) / 12; return mpt::ustring() .append(noteNames[(note - NOTE_MIN) % 12]) - .append(1, static_cast<mpt::uchar>(UC_('0') + ((note - NOTE_MIN) / 12))) + .append(1, static_cast<mpt::uchar>((octave <= 9 ? UC_('0') : UC_('A') - 10) + octave)) ; // e.g. "C#" + "5" } else if(note == NOTE_NONE) { @@ -2014,7 +2015,7 @@ if(targetIns == nullptr) return false; - return mpt::contains(mpt::as_span(targetIns->Keyboard).first(NOTE_MAX), sample); + return mpt::contains(mpt::as_span(targetIns->Keyboard).first(NOTE_MAX - NOTE_MIN + 1), sample); } Modified: trunk/OpenMPT/soundlib/mod_specifications.cpp ============================================================================== --- trunk/OpenMPT/soundlib/mod_specifications.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/mod_specifications.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -29,7 +29,7 @@ MOD_TYPE_MPT, // Internal MODTYPE value "mptm", // File extension NOTE_MIN, // Minimum note index - NOTE_MAX, // Maximum note index + NOTE_MIN + 119, // Maximum note index 4000, // Pattern max. 4000, // Order max. MAX_SEQUENCES, // Sequences max Modified: trunk/OpenMPT/soundlib/modcommand.h ============================================================================== --- trunk/OpenMPT/soundlib/modcommand.h Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/soundlib/modcommand.h Mon Nov 4 18:38:39 2024 (r22093) @@ -23,7 +23,7 @@ { NOTE_NONE = 0, // Empty note cell NOTE_MIN = 1, // Minimum note value - NOTE_MAX = 120, // Maximum note value + NOTE_MAX = 128, // Maximum note value NOTE_MIDDLEC = (5 * 12 + NOTE_MIN), NOTE_KEYOFF = 0xFF, // === (Note Off, releases envelope / fades samples, stops plugin note) NOTE_NOTECUT = 0xFE, // ^^^ (Cuts sample / stops all plugin notes) Modified: trunk/OpenMPT/test/test.cpp ============================================================================== --- trunk/OpenMPT/test/test.cpp Sun Nov 3 18:28:27 2024 (r22092) +++ trunk/OpenMPT/test/test.cpp Mon Nov 4 18:38:39 2024 (r22093) @@ -2863,6 +2863,9 @@ VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->instr, 0); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->volcmd, VOLCMD_VIBRATOSPEED); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->vol, 15); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 1)->note, NOTE_MIN + 12); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 1)->note, NOTE_MIN + 12 + 95); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(2, 1)->note, NOTE_KEYOFF); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 0)->IsEmpty(), true); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsEmpty(), false); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsPcNote(), false); @@ -3128,7 +3131,7 @@ VERIFY_EQUAL_NONCONT(pIns->pluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME); VERIFY_EQUAL_NONCONT(pIns->pluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI); - for(size_t i = 0; i < NOTE_MAX; i++) + for(size_t i = 0; i < 120; i++) { VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? (ins * 1111) : 1); VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], (i == NOTE_MIDDLEC - 1) ? (i + 13) : (i + 1)); @@ -3211,6 +3214,17 @@ VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->instr, 99); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->GetValueVolCol(), 1); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->GetValueEffectCol(), 200); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 0)->IsPcNote(), true); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 0)->note, NOTE_PCS); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 0)->instr, 250); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 0)->GetValueVolCol(), 999); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 0)->GetValueEffectCol(), 999); + + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 1)->note, NOTE_MIN); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(1, 1)->note, NOTE_MIN + 119); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(2, 1)->note, NOTE_KEYOFF); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(3, 1)->note, NOTE_NOTECUT); + VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(4, 1)->note, NOTE_FADE); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 0)->IsEmpty(), true); VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsEmpty(), false); Modified: trunk/OpenMPT/test/test.mptm ============================================================================== Binary file (source and/or target). No diff available. Modified: trunk/OpenMPT/test/test.xm ============================================================================== Binary file (source and/or target). No diff available. |