You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
(1) |
Apr
(1) |
May
|
Jun
(1) |
Jul
|
Aug
(10) |
Sep
|
Oct
|
Nov
|
Dec
(3) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(1) |
Feb
(2) |
Mar
(3) |
Apr
(2) |
May
(10) |
Jun
(2) |
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
(3) |
Dec
|
2008 |
Jan
(6) |
Feb
(4) |
Mar
(5) |
Apr
(2) |
May
(1) |
Jun
(1) |
Jul
(4) |
Aug
(6) |
Sep
(2) |
Oct
(9) |
Nov
(1) |
Dec
(4) |
2009 |
Jan
(9) |
Feb
(2) |
Mar
(2) |
Apr
(2) |
May
(6) |
Jun
(18) |
Jul
(33) |
Aug
(39) |
Sep
(33) |
Oct
(24) |
Nov
(23) |
Dec
(22) |
2010 |
Jan
(29) |
Feb
(32) |
Mar
(51) |
Apr
(17) |
May
(31) |
Jun
(21) |
Jul
(32) |
Aug
(28) |
Sep
(35) |
Oct
(27) |
Nov
(11) |
Dec
(13) |
2011 |
Jan
(14) |
Feb
(13) |
Mar
(27) |
Apr
(27) |
May
(28) |
Jun
(20) |
Jul
(43) |
Aug
(52) |
Sep
(66) |
Oct
(61) |
Nov
(11) |
Dec
(8) |
2012 |
Jan
(20) |
Feb
(30) |
Mar
(38) |
Apr
(21) |
May
(33) |
Jun
(21) |
Jul
(25) |
Aug
(9) |
Sep
(24) |
Oct
(42) |
Nov
(27) |
Dec
(41) |
2013 |
Jan
(20) |
Feb
(35) |
Mar
(156) |
Apr
(298) |
May
(258) |
Jun
(201) |
Jul
(105) |
Aug
(60) |
Sep
(193) |
Oct
(245) |
Nov
(280) |
Dec
(194) |
2014 |
Jan
(63) |
Feb
(202) |
Mar
(200) |
Apr
(23) |
May
(53) |
Jun
(105) |
Jul
(18) |
Aug
(26) |
Sep
(110) |
Oct
(187) |
Nov
(97) |
Dec
(74) |
2015 |
Jan
(45) |
Feb
(55) |
Mar
(116) |
Apr
(116) |
May
(193) |
Jun
(164) |
Jul
(50) |
Aug
(111) |
Sep
(98) |
Oct
(71) |
Nov
(103) |
Dec
(63) |
2016 |
Jan
(33) |
Feb
(101) |
Mar
(182) |
Apr
(139) |
May
(140) |
Jun
(103) |
Jul
(165) |
Aug
(286) |
Sep
(208) |
Oct
(127) |
Nov
(97) |
Dec
(54) |
2017 |
Jan
(64) |
Feb
(335) |
Mar
(202) |
Apr
(212) |
May
(139) |
Jun
(127) |
Jul
(294) |
Aug
(154) |
Sep
(170) |
Oct
(152) |
Nov
(156) |
Dec
(62) |
2018 |
Jan
(168) |
Feb
(237) |
Mar
(196) |
Apr
(174) |
May
(174) |
Jun
(161) |
Jul
(127) |
Aug
(88) |
Sep
(149) |
Oct
(66) |
Nov
(52) |
Dec
(135) |
2019 |
Jan
(146) |
Feb
(126) |
Mar
(104) |
Apr
(58) |
May
(60) |
Jun
(28) |
Jul
(197) |
Aug
(129) |
Sep
(141) |
Oct
(148) |
Nov
(63) |
Dec
(100) |
2020 |
Jan
(74) |
Feb
(37) |
Mar
(59) |
Apr
(154) |
May
(194) |
Jun
(133) |
Jul
(313) |
Aug
(197) |
Sep
(49) |
Oct
(162) |
Nov
(143) |
Dec
(57) |
2021 |
Jan
(120) |
Feb
(107) |
Mar
(314) |
Apr
(157) |
May
(524) |
Jun
(169) |
Jul
(72) |
Aug
(133) |
Sep
(135) |
Oct
(146) |
Nov
(198) |
Dec
(325) |
2022 |
Jan
(409) |
Feb
(249) |
Mar
(138) |
Apr
(95) |
May
(102) |
Jun
(221) |
Jul
(66) |
Aug
(120) |
Sep
(192) |
Oct
(131) |
Nov
(53) |
Dec
(171) |
2023 |
Jan
(357) |
Feb
(82) |
Mar
(168) |
Apr
(218) |
May
(196) |
Jun
(86) |
Jul
(115) |
Aug
(49) |
Sep
(190) |
Oct
(102) |
Nov
(45) |
Dec
(76) |
2024 |
Jan
(86) |
Feb
(50) |
Mar
(324) |
Apr
(209) |
May
(197) |
Jun
(232) |
Jul
(194) |
Aug
(247) |
Sep
(219) |
Oct
(266) |
Nov
(328) |
Dec
(304) |
2025 |
Jan
(191) |
Feb
(115) |
Mar
(137) |
Apr
(32) |
May
(126) |
Jun
(403) |
Jul
(213) |
Aug
(187) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <sv...@op...> - 2024-04-21 12:34:16
|
Author: sagamusix Date: Sun Apr 21 14:34:03 2024 New Revision: 20633 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20633 Log: [Imp] Support global S9x commands while seeking. Evaluate less commands when just retrieving song length. Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp Sun Apr 21 14:04:46 2024 (r20632) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp Sun Apr 21 14:34:03 2024 (r20633) @@ -715,22 +715,9 @@ case CMD_S3MCMDEX: switch(param & 0xF0) { - case 0x90: - if(param <= 0x91) - chn.dwFlags.set(CHN_SURROUND, param == 0x91); - break; - - case 0xA0: // High sample offset - chn.nOldHiOffset = param & 0x0F; - break; - case 0xB0: // Pattern Loop PatternLoop(playState, nChn, param & 0x0F); break; - - case 0xF0: // Active macro - chn.nActiveMacro = param & 0x0F; - break; } break; @@ -740,19 +727,9 @@ case 0x60: // Pattern Loop PatternLoop(playState, nChn, param & 0x0F); break; - - case 0xF0: // Active macro - chn.nActiveMacro = param & 0x0F; - break; } break; - case CMD_XFINEPORTAUPDOWN: - // ignore high offset in compatible mode - if(((param & 0xF0) == 0xA0) && !m_playBehaviour[kFT2RestrictXCommand]) - chn.nOldHiOffset = param & 0x0F; - break; - default: break; } @@ -873,22 +850,54 @@ Panning(chn, param, Pan8bit); break; case CMD_MODCMDEX: - if(param < 0x10) + switch(param & 0xF0) { - // LED filter + case 0x00: // LED filter for(CHANNELINDEX channel = 0; channel < GetNumChannels(); channel++) { playState.Chn[channel].dwFlags.set(CHN_AMIGAFILTER, !(param & 1)); } + break; + + case 0x80: // Panning + Panning(chn, (param & 0x0F), Pan4bit); + break; + + case 0xF0: // Active macro + chn.nActiveMacro = param & 0x0F; + break; } - [[fallthrough]]; + break; + case CMD_S3MCMDEX: - if((param & 0xF0) == 0x80) + switch(param & 0xF0) { + case 0x80: // Panning Panning(chn, (param & 0x0F), Pan4bit); + break; + + case 0x90: // Extended channel effects + // Change play direction is handled in adjustSamplePos case + if (param < 0x9E) + ExtendedChannelEffect(chn, param, playState); + break; + + case 0xA0: // High sample offset + chn.nOldHiOffset = param & 0x0F; + break; + + case 0xF0: // Active macro + chn.nActiveMacro = param & 0x0F; + break; } break; + case CMD_XFINEPORTAUPDOWN: + // ignore high offset in compatible mode + if (((param & 0xF0) == 0xA0) && !m_playBehaviour[kFT2RestrictXCommand]) + chn.nOldHiOffset = param & 0x0F; + break; + case CMD_VIBRATOVOL: if (param) chn.nOldVolumeSlide = param; param = 0; @@ -945,7 +954,6 @@ case CMD_VIBRATO: case CMD_FINEVIBRATO: case CMD_VIBRATOVOL: - if(adjustMode & eAdjust) { uint32 vibTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks; uint32 inc = chn.nVibratoSpeed * vibTicks; @@ -956,7 +964,6 @@ break; case CMD_TREMOLO: - if(adjustMode & eAdjust) { uint32 tremTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks; uint32 inc = chn.nTremoloSpeed * tremTicks; @@ -967,12 +974,9 @@ break; case CMD_PANBRELLO: - if(adjustMode & eAdjust) - { - // Panbrello effect is permanent in compatible mode, so actually apply panbrello for the last tick of this row - chn.nPanbrelloPos += static_cast<uint8>(chn.nPanbrelloSpeed * (numTicks - 1)); - ProcessPanbrello(chn); - } + // Panbrello effect is permanent in compatible mode, so actually apply panbrello for the last tick of this row + chn.nPanbrelloPos += static_cast<uint8>(chn.nPanbrelloSpeed * nonRowTicks); + ProcessPanbrello(chn); break; default: @@ -1162,19 +1166,13 @@ break; case CMD_S3MCMDEX: - if(m.param == 0x9E) - { - // Play forward - memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far - chn.dwFlags.reset(CHN_PINGPONGFLAG); - } else if(m.param == 0x9F) + if((m.param & 0xF0) == 0x90) { - // Reverse - memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far - chn.dwFlags.set(CHN_PINGPONGFLAG); - if(!chn.position.GetInt() && chn.nLength && (m.IsNote() || !chn.dwFlags[CHN_LOOP])) + // Change play direction - other cases already handled above + if(m.param == 0x9E || m.param == 0x9F) { - chn.position.Set(chn.nLength - 1, SamplePosition::fractMax); + memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far + ExtendedChannelEffect(chn, m.param, playState); } } else if((m.param & 0xF0) == 0x70) { @@ -4828,7 +4826,11 @@ } break; // S9x: Sound Control - case 0x90: ExtendedChannelEffect(chn, param); break; + case 0x90: + if(m_PlayState.m_flags[SONG_FIRSTTICK]) + { + ExtendedChannelEffect(chn, param, m_PlayState); break; + } // SAx: Set 64k Offset case 0xA0: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { @@ -4873,16 +4875,15 @@ } -void CSoundFile::ExtendedChannelEffect(ModChannel &chn, uint32 param) +void CSoundFile::ExtendedChannelEffect(ModChannel &chn, uint32 param, PlayState &playState) const { // S9x and X9x commands (S3M/XM/IT only) - if(!m_PlayState.m_flags[SONG_FIRSTTICK]) return; switch(param & 0x0F) { // S90: Surround Off - case 0x00: chn.dwFlags.reset(CHN_SURROUND); break; + case 0x00: chn.dwFlags.reset(CHN_SURROUND); break; // S91: Surround On - case 0x01: chn.dwFlags.set(CHN_SURROUND); chn.nPan = 128; break; + case 0x01: chn.dwFlags.set(CHN_SURROUND); chn.nPan = 128; break; //////////////////////////////////////////////////////////// // ModPlug Extensions @@ -4898,19 +4899,19 @@ break; // S9A: 2-Channels surround mode case 0x0A: - m_PlayState.m_flags.reset(SONG_SURROUNDPAN); + playState.m_flags.reset(SONG_SURROUNDPAN); break; // S9B: 4-Channels surround mode case 0x0B: - m_PlayState.m_flags.set(SONG_SURROUNDPAN); + playState.m_flags.set(SONG_SURROUNDPAN); break; // S9C: IT Filter Mode case 0x0C: - m_PlayState.m_flags.reset(SONG_MPTFILTERMODE); + playState.m_flags.reset(SONG_MPTFILTERMODE); break; // S9D: MPT Filter Mode case 0x0D: - m_PlayState.m_flags.set(SONG_MPTFILTERMODE); + playState.m_flags.set(SONG_MPTFILTERMODE); break; // S9E: Go forward case 0x0E: Modified: trunk/OpenMPT/soundlib/Sndfile.h ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h Sun Apr 21 14:04:46 2024 (r20632) +++ trunk/OpenMPT/soundlib/Sndfile.h Sun Apr 21 14:34:03 2024 (r20633) @@ -1155,7 +1155,7 @@ bool HandleNextRow(PlayState &state, const ModSequence &order, bool honorPatternLoop) const; void ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param); void ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param); - void ExtendedChannelEffect(ModChannel &chn, uint32 param); + void ExtendedChannelEffect(ModChannel &chn, uint32 param, PlayState &playState) const; void InvertLoop(ModChannel &chn); void PositionJump(PlayState &state, CHANNELINDEX chn) const; ROWINDEX PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 param) const; |
From: <sv...@op...> - 2024-04-21 12:04:56
|
Author: sagamusix Date: Sun Apr 21 14:04:46 2024 New Revision: 20632 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20632 Log: [Fix] Compile fix for libopenmpt. Modified: trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp Modified: trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp ============================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp Sun Apr 21 13:52:16 2024 (r20631) +++ trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp Sun Apr 21 14:04:46 2024 (r20632) @@ -523,7 +523,7 @@ } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call - m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED); + m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } @@ -546,7 +546,7 @@ } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call - m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED); + m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } @@ -568,7 +568,7 @@ } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call - m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED); + m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } @@ -590,7 +590,7 @@ } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call - m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED); + m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } |
From: <sv...@op...> - 2024-04-21 11:52:28
|
Author: sagamusix Date: Sun Apr 21 13:52:16 2024 New Revision: 20631 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20631 Log: [Ref] Move play state related SONG_* flags to their own flag set in m_PlayState. Modified: trunk/OpenMPT/mptrack/CleanupSong.cpp trunk/OpenMPT/mptrack/Ctrl_pat.cpp trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/OPLExport.cpp trunk/OpenMPT/mptrack/SampleTrimmer.cpp trunk/OpenMPT/mptrack/View_ins.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/mod2midi.cpp 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/Sndmix.cpp trunk/OpenMPT/test/test.cpp Modified: trunk/OpenMPT/mptrack/CleanupSong.cpp ============================================================================== --- trunk/OpenMPT/mptrack/CleanupSong.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/CleanupSong.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -552,7 +552,7 @@ { sndFile.ResetPlayPos(); sndFile.GetLength(eAdjust, GetLengthTarget(song.startOrder, song.startRow).StartPos(song.sequence, 0, 0)); - sndFile.m_SongFlags.reset(SONG_PLAY_FLAGS); + sndFile.m_PlayState.m_flags.reset(); while(!m_abort) { auto tickSamples = sndFile.ReadOneTick(); Modified: trunk/OpenMPT/mptrack/Ctrl_pat.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/Ctrl_pat.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -440,7 +440,7 @@ case CTRLMSG_SETVIEWWND: { SendViewMessage(VIEWMSG_FOLLOWSONG, IsDlgButtonChecked(IDC_PATTERN_FOLLOWSONG)); - SendViewMessage(VIEWMSG_PATTERNLOOP, (m_sndFile.m_SongFlags & SONG_PATTERNLOOP) ? TRUE : FALSE); + SendViewMessage(VIEWMSG_PATTERNLOOP, (m_sndFile.m_PlayState.m_flags[SONG_PATTERNLOOP]) ? TRUE : FALSE); OnSpacingChanged(); SendViewMessage(VIEWMSG_SETDETAIL, m_nDetailLevel); SendViewMessage(VIEWMSG_SETRECORD, m_bRecord); @@ -493,13 +493,13 @@ if (lParam == -1) { //Toggle loop state - setLoop = !m_sndFile.m_SongFlags[SONG_PATTERNLOOP]; + setLoop = !m_sndFile.m_PlayState.m_flags[SONG_PATTERNLOOP]; } else { setLoop = (lParam != 0); } - m_sndFile.m_SongFlags.set(SONG_PATTERNLOOP, setLoop); + m_sndFile.m_PlayState.m_flags.set(SONG_PATTERNLOOP, setLoop); CheckDlgButton(IDC_PATTERN_LOOP, setLoop ? BST_CHECKED : BST_UNCHECKED); break; } Modified: trunk/OpenMPT/mptrack/Ctrl_seq.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -385,23 +385,23 @@ const bool isPlaying = IsPlaying(); bool changedPos = false; - if(isPlaying && sndFile.m_SongFlags[SONG_PATTERNLOOP]) + if(isPlaying && sndFile.m_PlayState.m_flags[SONG_PATTERNLOOP]) { pMainFrm->ResetNotificationBuffer(); // Update channel parameters and play time CriticalSection cs; - m_modDoc.SetElapsedTime(m_nScrollPos, 0, !sndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]); + m_modDoc.SetElapsedTime(m_nScrollPos, 0, !sndFile.m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]); changedPos = true; } else if(m_pParent.GetFollowSong()) { - FlagSet<SongFlags> pausedFlags = sndFile.m_SongFlags & (SONG_PAUSED | SONG_STEP | SONG_PATTERNLOOP); + FlagSet<PlayFlags> pausedFlags = sndFile.m_PlayState.m_flags & (SONG_PAUSED | SONG_STEP | SONG_PATTERNLOOP); // Update channel parameters and play time CriticalSection cs; sndFile.SetCurrentOrder(m_nScrollPos); - m_modDoc.SetElapsedTime(m_nScrollPos, 0, !sndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]); - sndFile.m_SongFlags.set(pausedFlags); + m_modDoc.SetElapsedTime(m_nScrollPos, 0, !sndFile.m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]); + sndFile.m_PlayState.m_flags.set(pausedFlags); if(isPlaying) pMainFrm->ResetNotificationBuffer(); Modified: trunk/OpenMPT/mptrack/MainFrm.cpp ============================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/MainFrm.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -1037,7 +1037,7 @@ m_pSndFile->ResetMixStat(); - if(m_pSndFile->m_SongFlags[SONG_ENDREACHED]) notification.type.set(Notification::EOS); + if(m_pSndFile->m_PlayState.m_flags[SONG_ENDREACHED]) notification.type.set(Notification::EOS); if(notifyType[Notification::Sample]) { @@ -1048,7 +1048,7 @@ for(CHANNELINDEX k = 0; k < MAX_CHANNELS; k++) { const ModChannel &chn = m_pSndFile->m_PlayState.Chn[k]; - if(chn.pModSample == &m_pSndFile->GetSample(smp) && chn.nLength != 0 // Corrent sample is set up on this channel + if(chn.pModSample == &m_pSndFile->GetSample(smp) && chn.nLength != 0 // Correct sample is set up on this channel && (!chn.dwFlags[CHN_NOTEFADE] || chn.nFadeOutVol)) // And it hasn't completely faded out yet, so it's still playing { notification.pos[k] = chn.position.GetInt(); @@ -1359,7 +1359,7 @@ { m_wndTree.UpdatePlayPos(m_pSndFile->GetpModDoc(), nullptr); } - m_pSndFile->m_SongFlags.reset(SONG_PAUSED); + m_pSndFile->m_PlayState.m_flags.reset(SONG_PAUSED); if(m_pSndFile == &m_WaveFile) { // Unload previewed instrument @@ -1412,11 +1412,11 @@ SetPlaybackSoundFile(&sndFile); const bool bPaused = m_pSndFile->IsPaused(); - const bool bPatLoop = m_pSndFile->m_SongFlags[SONG_PATTERNLOOP]; + const bool bPatLoop = m_pSndFile->m_PlayState.m_flags[SONG_PATTERNLOOP]; - m_pSndFile->m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED); + m_pSndFile->m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); - if(!bPatLoop && bPaused) sndFile.m_SongFlags.set(SONG_PAUSED); + if(!bPatLoop && bPaused) sndFile.m_PlayState.m_flags.set(SONG_PAUSED); sndFile.SetRepeatCount((TrackerSettings::Instance().gbLoopSong) ? -1 : 0); sndFile.InitPlayer(true); @@ -1582,7 +1582,7 @@ if(file.IsValid()) { InitPreview(); - m_WaveFile.m_SongFlags.set(SONG_PAUSED); + m_WaveFile.m_PlayState.m_flags.set(SONG_PAUSED); // Avoid hanging audio while reading file - we have removed all sample and instrument references before, // so it's safe to replace the sample / instrument now. cs.Leave(); @@ -1690,7 +1690,7 @@ } return; } - m_WaveFile.m_SongFlags.reset(SONG_PAUSED); + m_WaveFile.m_PlayState.m_flags.reset(SONG_PAUSED); m_WaveFile.SetRepeatCount(-1); m_WaveFile.ResetPlayPos(); @@ -2587,7 +2587,7 @@ { case kcPrevOrder: case kcNextOrder: - m_pSndFile->GetpModDoc()->SetElapsedTime(order, 0, !m_pSndFile->m_SongFlags[SONG_PAUSED | SONG_STEP]); + m_pSndFile->GetpModDoc()->SetElapsedTime(order, 0, !m_pSndFile->m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]); break; case kcPrevOrderAtMeasureEnd: case kcNextOrderAtMeasureEnd: @@ -3165,7 +3165,7 @@ void CMainFrame::NotifyAccessibilityUpdate(CWnd &source) { - if(!IsPlaying() || m_pSndFile->m_SongFlags[SONG_PAUSED]) + if(!IsPlaying() || m_pSndFile->m_PlayState.m_flags[SONG_PAUSED]) source.NotifyWinEvent(EVENT_OBJECT_NAMECHANGE, OBJID_CLIENT, CHILDID_SELF); } Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -978,7 +978,7 @@ mixersettings.m_nMaxMixChannels = MAX_CHANNELS; // always use max mixing channels when rendering mixersettings.gdwMixingFreq = samplerate; mixersettings.gnChannels = channels; - m_SndFile.m_SongFlags.reset(SONG_PAUSED | SONG_STEP); + m_SndFile.m_PlayState.m_flags.reset(SONG_PAUSED | SONG_STEP); if(m_Settings.normalize) { #ifndef NO_AGC @@ -1062,7 +1062,7 @@ // Reset song position tracking m_SndFile.ResetPlayPos(); - m_SndFile.m_SongFlags.reset(SONG_PATTERNLOOP); + m_SndFile.m_PlayState.m_flags.reset(SONG_PATTERNLOOP); ORDERINDEX startOrder = 0; GetLengthTarget target; if(m_Settings.minOrder != ORDERINDEX_INVALID && m_Settings.maxOrder != ORDERINDEX_INVALID) @@ -1110,7 +1110,7 @@ auto mainFrame = CMainFrame::GetMainFrame(); mainFrame->PauseMod(); - m_SndFile.m_SongFlags.reset(SONG_STEP | SONG_PATTERNLOOP); + m_SndFile.m_PlayState.m_flags.reset(SONG_STEP | SONG_PATTERNLOOP); mainFrame->InitRenderer(&m_SndFile); while(true) Modified: trunk/OpenMPT/mptrack/ModConvert.cpp ============================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/ModConvert.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -566,7 +566,7 @@ m_SndFile.m_SongFlags.set(SONG_ISAMIGA); m_SndFile.InitAmigaResampler(); } - m_SndFile.m_SongFlags &= (specs.songFlags | SONG_PLAY_FLAGS); + m_SndFile.m_SongFlags &= specs.songFlags; // Adjust mix levels if(newTypeIsMOD || newTypeIsS3M) Modified: trunk/OpenMPT/mptrack/Moddoc.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/Moddoc.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -1036,7 +1036,7 @@ // All notes off when resuming paused playback m_SndFile.ResetChannels(); - m_SndFile.m_SongFlags.set(SONG_PAUSED); + m_SndFile.m_PlayState.m_flags.set(SONG_PAUSED); pMainFrm->PlayMod(this); } @@ -2131,7 +2131,7 @@ } const bool isPlaying = (pMainFrm->GetModPlaying() == this); - if(isPlaying && !m_SndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]) + if(isPlaying && !m_SndFile.m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]) { OnPlayerPause(); return; @@ -2146,7 +2146,7 @@ if (!isPlaying) m_SndFile.m_PlayState.Chn[i].nLength = 0; } - m_SndFile.m_PlayState.m_bPositionChanged = true; + m_SndFile.m_PlayState.m_flags.set(SONG_POSITIONCHANGED); if(isPlaying) { @@ -2155,7 +2155,7 @@ cs.Leave(); - m_SndFile.m_SongFlags.reset(SONG_STEP | SONG_PAUSED | SONG_PATTERNLOOP); + m_SndFile.m_PlayState.m_flags.reset(SONG_STEP | SONG_PAUSED | SONG_PATTERNLOOP); pMainFrm->PlayMod(this); } } @@ -2168,7 +2168,7 @@ { if (pMainFrm->GetModPlaying() == this) { - bool isLooping = m_SndFile.m_SongFlags[SONG_PATTERNLOOP]; + bool isLooping = m_SndFile.m_PlayState.m_flags[SONG_PATTERNLOOP]; PATTERNINDEX nPat = m_SndFile.m_PlayState.m_nPattern; ROWINDEX nRow = m_SndFile.m_PlayState.m_nRow; ROWINDEX nNextRow = m_SndFile.m_PlayState.m_nNextRow; @@ -2228,11 +2228,11 @@ pMainFrm->PauseMod(); CriticalSection cs; - m_SndFile.m_SongFlags.reset(SONG_STEP | SONG_PATTERNLOOP); + m_SndFile.m_PlayState.m_flags.reset(SONG_STEP | SONG_PATTERNLOOP); m_SndFile.ResetPlayPos(); //m_SndFile.visitedSongRows.Initialize(true); - m_SndFile.m_PlayState.m_bPositionChanged = true; + m_SndFile.m_PlayState.m_flags.set(SONG_POSITIONCHANGED); cs.Leave(); @@ -2537,7 +2537,7 @@ chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } 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.m_PlayState.m_flags.reset(SONG_PAUSED | SONG_STEP); if(loop) m_SndFile.LoopPattern(nPat); else @@ -2590,7 +2590,7 @@ m_SndFile.m_PlayState.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } 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.m_PlayState.m_flags.reset(SONG_PAUSED | SONG_STEP); m_SndFile.LoopPattern(nPat); // set playback timer in the status bar (and update channel status) @@ -2639,7 +2639,7 @@ { m_SndFile.m_PlayState.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } - m_SndFile.m_SongFlags.reset(SONG_PAUSED | SONG_STEP); + m_SndFile.m_PlayState.m_flags.reset(SONG_PAUSED | SONG_STEP); m_SndFile.SetCurrentOrder(nOrd); if(nOrd < m_SndFile.Order().size() && m_SndFile.Order()[nOrd] == nPat) m_SndFile.DontLoopPattern(nPat, nRow); @@ -2737,7 +2737,7 @@ case kcPlayPatternFromCursor: OnPatternPlay(); break; case kcPlayPatternFromStart: OnPatternRestart(); break; case kcPlaySongFromCursorPause: - if(CMainFrame::GetMainFrame()->GetModPlaying() == this && !m_SndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]) + if(CMainFrame::GetMainFrame()->GetModPlaying() == this && !m_SndFile.m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]) { OnPlayerPause(); break; @@ -2746,7 +2746,7 @@ case kcPlaySongFromCursor: OnPatternPlayNoLoop(); break; case kcPlaySongFromStart: OnPlayerPlayFromStart(); break; case kcPlayStopSong: - if(CMainFrame::GetMainFrame()->GetModPlaying() == this && !m_SndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]) + if(CMainFrame::GetMainFrame()->GetModPlaying() == this && !m_SndFile.m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]) { OnPlayerStop(); break; @@ -2754,7 +2754,7 @@ [[fallthrough]]; case kcPlayPauseSong: OnPlayerPlay(); break; case kcPlaySongFromPatternPause: - if(CMainFrame::GetMainFrame()->GetModPlaying() == this && !m_SndFile.m_SongFlags[SONG_PAUSED | SONG_STEP]) + if(CMainFrame::GetMainFrame()->GetModPlaying() == this && !m_SndFile.m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]) { OnPlayerPause(); break; Modified: trunk/OpenMPT/mptrack/OPLExport.cpp ============================================================================== --- trunk/OpenMPT/mptrack/OPLExport.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/OPLExport.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -535,7 +535,7 @@ m_sndFile.ResetPlayPos(); m_sndFile.GetLength(eAdjust, GetLengthTarget(song.startOrder, song.startRow).StartPos(song.sequence, 0, 0)); - m_sndFile.m_SongFlags.reset(SONG_PLAY_FLAGS); + m_sndFile.m_PlayState.m_flags.reset(); m_oplLogger.Reset(); m_sndFile.m_opl = std::make_unique<OPL>(m_oplLogger); @@ -571,7 +571,7 @@ } } - if(m_sndFile.m_SongFlags[SONG_BREAKTOROW] && loopStart == Util::MaxValueOfType(loopStart) && song.loopStartOrder == song.startOrder && song.loopStartRow == song.startRow) + if(m_sndFile.m_PlayState.m_flags[SONG_BREAKTOROW] && loopStart == Util::MaxValueOfType(loopStart) && song.loopStartOrder == song.startOrder && song.loopStartRow == song.startRow) loopStart = 0; mpt::PathString currentFileName = fileName; Modified: trunk/OpenMPT/mptrack/SampleTrimmer.cpp ============================================================================== --- trunk/OpenMPT/mptrack/SampleTrimmer.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/SampleTrimmer.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -75,7 +75,7 @@ const auto &song = subSongs[i]; m_SndFile.ResetPlayPos(); m_SndFile.GetLength(eAdjust, GetLengthTarget(song.startOrder, song.startRow).StartPos(song.sequence, 0, 0)); - m_SndFile.m_SongFlags.reset(SONG_PLAY_FLAGS); + m_SndFile.m_PlayState.m_flags.reset(); size_t subsongSamples = 0; DummyAudioTarget target; Modified: trunk/OpenMPT/mptrack/View_ins.cpp ============================================================================== --- trunk/OpenMPT/mptrack/View_ins.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/View_ins.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -2024,7 +2024,7 @@ { if(pMainFrm->GetModPlaying() != pModDoc) { - sndFile.m_SongFlags.set(SONG_PAUSED); + sndFile.m_PlayState.m_flags.set(SONG_PAUSED); sndFile.ResetChannels(); if(!pMainFrm->PlayMod(pModDoc)) return; Modified: trunk/OpenMPT/mptrack/View_pat.cpp ============================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/View_pat.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -2240,8 +2240,8 @@ } sndFile.LoopPattern(m_nPattern); sndFile.m_PlayState.m_nNextRow = row == ROWINDEX_INVALID ? GetCurrentRow() : row; - sndFile.m_SongFlags.reset(SONG_PAUSED); - sndFile.m_SongFlags.set(SONG_STEP); + sndFile.m_PlayState.m_flags.reset(SONG_PAUSED); + sndFile.m_PlayState.m_flags.set(SONG_STEP); SetPlayCursor(m_nPattern, sndFile.m_PlayState.m_nNextRow, 0); cs.Leave(); @@ -3558,7 +3558,7 @@ } m_nLastPlayedRow = row; - if(!pSndFile->m_SongFlags[SONG_PAUSED | SONG_STEP]) + if(!pSndFile->m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]) { const auto &order = Order(); if(ord >= order.GetLength() || order[ord] != pat) @@ -5436,7 +5436,7 @@ } const bool liveRecord = IsLiveRecord(); - const bool usePlaybackPosition = (liveRecord && (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_AUTODELAY) && !sndFile.m_SongFlags[SONG_STEP]); + const bool usePlaybackPosition = (liveRecord && (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_AUTODELAY) && !sndFile.m_PlayState.m_flags[SONG_STEP]); const bool isSpecial = note >= NOTE_MIN_SPECIAL; const bool isSplit = IsNoteSplit(note); @@ -6122,7 +6122,7 @@ if(!sndFile->Patterns[pat].IsValidRow(row)) { // Quantization exceeds current pattern, try stuffing note into next pattern instead. - PATTERNINDEX nextPat = sndFile->m_SongFlags[SONG_PATTERNLOOP] ? m_nPattern : GetNextPattern(); + PATTERNINDEX nextPat = sndFile->m_PlayState.m_flags[SONG_PATTERNLOOP] ? m_nPattern : GetNextPattern(); if(nextPat != PATTERNINDEX_INVALID) { pat = nextPat; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp ============================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/Vstplug.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -321,7 +321,7 @@ if(pVstPlugin->IsSongPlaying()) { timeInfo.flags |= kVstTransportPlaying; - if(pVstPlugin->GetSoundFile().m_SongFlags[SONG_PATTERNLOOP]) timeInfo.flags |= kVstTransportCycleActive; + if(pVstPlugin->GetSoundFile().m_PlayState.m_flags[SONG_PATTERNLOOP]) timeInfo.flags |= kVstTransportCycleActive; timeInfo.samplePos = sndFile.GetTotalSampleCount(); if(pVstPlugin->m_positionChanged) { Modified: trunk/OpenMPT/mptrack/mod2midi.cpp ============================================================================== --- trunk/OpenMPT/mptrack/mod2midi.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/mptrack/mod2midi.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -857,7 +857,7 @@ m_sndFile.SetCurrentOrder(0); m_sndFile.GetLength(eAdjust, GetLengthTarget(0, 0)); - m_sndFile.m_SongFlags.reset(SONG_PATTERNLOOP); + m_sndFile.m_PlayState.m_flags.reset(SONG_PATTERNLOOP); int oldRepCount = m_sndFile.GetRepeatCount(); m_sndFile.SetRepeatCount(0); m_sndFile.m_bIsRendering = true; Modified: trunk/OpenMPT/soundlib/Snd_defs.h ============================================================================== --- trunk/OpenMPT/soundlib/Snd_defs.h Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/soundlib/Snd_defs.h Sun Apr 21 13:52:16 2024 (r20631) @@ -242,36 +242,41 @@ }; +enum PlayFlags : uint16 +{ + SONG_PATTERNLOOP = 0x01, // Loop current pattern (pattern editor) + SONG_STEP = 0x02, // Song is in "step" mode (pattern editor) + SONG_PAUSED = 0x04, // Song is paused (no tick processing, just rendering audio) + SONG_FADINGSONG = 0x08, // Song is fading out + SONG_ENDREACHED = 0x10, // Song is finished + SONG_FIRSTTICK = 0x20, // Is set when the current tick is the first tick of the row + SONG_MPTFILTERMODE = 0x40, // Local filter mode (reset filter on each note) + SONG_SURROUNDPAN = 0x80, // Pan in the rear channels + SONG_POSJUMP = 0x100, // Position jump encountered (internal flag, do not touch) + SONG_BREAKTOROW = 0x200, // Break to row command encountered (internal flag, do not touch) + SONG_POSITIONCHANGED = 0x400, // Report to plugins that we jumped around in the module +}; +DECLARE_FLAGSET(PlayFlags) + + // Module flags - contains both song configuration and playback state... Use SONG_FILE_FLAGS and SONG_PLAY_FLAGS distinguish between the two. enum SongFlags { - SONG_FASTPORTAS = 0x01, // Portamentos are executed on every tick - SONG_FASTVOLSLIDES = 0x02, // Old Scream Tracker 3.0 volume slides (executed on every tick) - SONG_ITOLDEFFECTS = 0x04, // Old Impulse Tracker effect implementations - SONG_ITCOMPATGXX = 0x08, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) - SONG_LINEARSLIDES = 0x10, // Linear slides vs. Amiga slides - SONG_PATTERNLOOP = 0x20, // Loop current pattern (pattern editor) - SONG_STEP = 0x40, // Song is in "step" mode (pattern editor) - SONG_PAUSED = 0x80, // Song is paused (no tick processing, just rendering audio) - SONG_FADINGSONG = 0x0100, // Song is fading out - SONG_ENDREACHED = 0x0200, // Song is finished - SONG_FIRSTTICK = 0x1000, // Is set when the current tick is the first tick of the row - SONG_MPTFILTERMODE = 0x2000, // Local filter mode (reset filter on each note) - SONG_SURROUNDPAN = 0x4000, // Pan in the rear channels - SONG_EXFILTERRANGE = 0x8000, // Cutoff Filter has double frequency range (up to ~10Khz) - SONG_AMIGALIMITS = 0x1'0000, // Enforce amiga frequency limits - SONG_S3MOLDVIBRATO = 0x2'0000, // ScreamTracker 2 vibrato in S3M files - SONG_BREAKTOROW = 0x8'0000, // Break to row command encountered (internal flag, do not touch) - SONG_POSJUMP = 0x10'0000, // Position jump encountered (internal flag, do not touch) - SONG_PT_MODE = 0x20'0000, // ProTracker 1/2 playback mode - SONG_PLAYALLSONGS = 0x40'0000, // Play all subsongs consecutively (libopenmpt) - SONG_ISAMIGA = 0x80'0000, // Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler - SONG_IMPORTED = 0x100'0000, // Song type does not represent actual module format / was imported from a different format (OpenMPT) + SONG_FASTPORTAS = 0x01, // Portamentos are executed on every tick + SONG_FASTVOLSLIDES = 0x02, // Old Scream Tracker 3.0 volume slides (executed on every tick) + SONG_ITOLDEFFECTS = 0x04, // Old Impulse Tracker effect implementations + SONG_ITCOMPATGXX = 0x08, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) + SONG_LINEARSLIDES = 0x10, // Linear slides vs. Amiga slides + SONG_EXFILTERRANGE = 0x20, // Cutoff Filter has double frequency range (up to ~10Khz) + SONG_AMIGALIMITS = 0x40, // Enforce amiga frequency limits + SONG_S3MOLDVIBRATO = 0x80, // ScreamTracker 2 vibrato in S3M files + SONG_PT_MODE = 0x100, // ProTracker 1/2 playback mode + SONG_ISAMIGA = 0x200, // Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler + SONG_IMPORTED = 0x400, // Song type does not represent actual module format / was imported from a different format (OpenMPT) + SONG_PLAYALLSONGS = 0x800, // Play all subsongs consecutively (libopenmpt) }; DECLARE_FLAGSET(SongFlags) -#define SONG_FILE_FLAGS (SONG_FASTPORTAS|SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_S3MOLDVIBRATO|SONG_PT_MODE|SONG_ISAMIGA|SONG_IMPORTED) -#define SONG_PLAY_FLAGS (~SONG_FILE_FLAGS) // Global Options (Renderer) #ifndef NO_AGC Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -1282,7 +1282,7 @@ m_PlayState.m_nNextRow = m_PlayState.m_nRow; m_PlayState.m_nFrameDelay = m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; - m_PlayState.m_bPositionChanged = true; + m_PlayState.m_flags.set(SONG_POSITIONCHANGED); if(m_opl != nullptr) m_opl->Reset(); for(CHANNELINDEX n = 0; n < GetNumChannels(); n++) @@ -2108,7 +2108,7 @@ chn.SetInstrumentPan(newPan, *this); // IT compatibility: Sample and instrument panning overrides channel surround status. // Test case: SmpInsPanSurround.it - if(m_playBehaviour[kPanOverride] && !m_SongFlags[SONG_SURROUNDPAN]) + if(m_playBehaviour[kPanOverride] && !m_PlayState.m_flags[SONG_SURROUNDPAN]) { chn.dwFlags.reset(CHN_SURROUND); } @@ -2460,7 +2460,7 @@ bool bPorta = chn.rowCommand.IsPortamento(); uint32 nStartTick = 0; - chn.isFirstTick = m_SongFlags[SONG_FIRSTTICK]; + chn.isFirstTick = m_PlayState.m_flags[SONG_FIRSTTICK]; // Process parameter control note. if(chn.rowCommand.note == NOTE_PC) @@ -2484,7 +2484,7 @@ if(chn.rowCommand.note == NOTE_PCS || (cmd == CMD_NONE && chn.m_plugParamValueStep != 0)) { #ifndef NO_PLUGINS - const bool isFirstTick = m_SongFlags[SONG_FIRSTTICK]; + const bool isFirstTick = m_PlayState.m_flags[SONG_FIRSTTICK]; if(isFirstTick) chn.m_RowPlug = chn.rowCommand.instr; const PLUGINDEX plugin = chn.m_RowPlug; @@ -2524,7 +2524,7 @@ } // Process Invert Loop (MOD Effect, called every row if it's active) - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { InvertLoop(m_PlayState.Chn[nChn]); } else @@ -2568,7 +2568,7 @@ } continue; } - } else if(m_SongFlags[SONG_FIRSTTICK]) + } else if(m_PlayState.m_flags[SONG_FIRSTTICK]) { // Pattern Loop ? if((param & 0xF0) == 0xE0) @@ -2728,9 +2728,9 @@ retrigEnv = false; // FT2 Compatbility: Start fading the note for notes with no delay. Only relevant when a volume command is encountered after the note-off. // Test case: NoteOffFadeNoEnv.xm - if(m_SongFlags[SONG_FIRSTTICK] && m_playBehaviour[kFT2NoteOffFlags]) + if(m_PlayState.m_flags[SONG_FIRSTTICK] && m_playBehaviour[kFT2NoteOffFlags]) chn.dwFlags.set(CHN_NOTEFADE); - } else if(m_playBehaviour[kFT2RetrigWithNoteDelay] && !m_SongFlags[SONG_FIRSTTICK]) + } else if(m_playBehaviour[kFT2RetrigWithNoteDelay] && !m_PlayState.m_flags[SONG_FIRSTTICK]) { // FT2 Compatibility: Some special hacks for rogue note delays... (EDx with x > 0) // Apparently anything that is next to a note delay behaves totally unpredictable in FT2. Swedish tracker logic. :) @@ -3029,7 +3029,7 @@ case VOLCMD_PANSLIDELEFT: // FT2 Compatibility: Pan slide left with zero parameter causes panning to be set to full left on every non-row tick. // Test case: PanSlideZero.xm - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nPan = 0; } @@ -3144,14 +3144,14 @@ { // Set Volume case CMD_VOLUME: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nVolume = (param < 64) ? param * 4 : 256; chn.dwFlags.set(CHN_FASTVOLRAMP); } break; case CMD_VOLUME8: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nVolume = param; chn.dwFlags.set(CHN_FASTVOLRAMP); @@ -3199,7 +3199,7 @@ // Set Speed case CMD_SPEED: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) SetSpeed(m_PlayState, param); break; @@ -3208,7 +3208,7 @@ if(m_playBehaviour[kMODVBlankTiming]) { // ProTracker MODs with VBlank timing: All Fxx parameters set the tick count. - if(m_SongFlags[SONG_FIRSTTICK] && param != 0) SetSpeed(m_PlayState, param); + if(m_PlayState.m_flags[SONG_FIRSTTICK] && param != 0) SetSpeed(m_PlayState, param); break; } { @@ -3279,7 +3279,7 @@ // Tremor case CMD_TREMOR: - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { break; } @@ -3313,11 +3313,11 @@ case CMD_GLOBALVOLUME: // IT compatibility: Only apply global volume on first tick (and multiples) // Test case: GlobalVolFirstTick.it - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; // ST3 applies global volume on tick 1 and does other weird things, but we won't emulate this for now. // if(((GetType() & MOD_TYPE_S3M) && m_nTickCount != 1) -// || (!(GetType() & MOD_TYPE_S3M) && !m_SongFlags[SONG_FIRSTTICK])) +// || (!(GetType() & MOD_TYPE_S3M) && !m_PlayState.m_flags[SONG_FIRSTTICK])) // { // break; // } @@ -3326,7 +3326,7 @@ // until the second tick of the row. Since we apply global volume on the mix buffer rather than note volumes, this // cannot be fixed for now. // Test case: GlobalVolume.xm -// if(IsCompatibleMode(TRK_FASTTRACKER2) && m_SongFlags[SONG_FIRSTTICK] && m_nMusicSpeed > 1) +// if(IsCompatibleMode(TRK_FASTTRACKER2) && m_PlayState.m_flags[SONG_FIRSTTICK] && m_nMusicSpeed > 1) // { // break; // } @@ -3355,7 +3355,7 @@ // Set 8-bit Panning case CMD_PANNING8: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { Panning(chn, param, Pan8bit); } @@ -3412,7 +3412,7 @@ // This is how it's NOT supposed to sound... else { - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) KeyOff(chn); } break; @@ -3444,13 +3444,13 @@ case CMD_FINETUNE: case CMD_FINETUNE_SMOOTH: - if(m_SongFlags[SONG_FIRSTTICK] || cmd == CMD_FINETUNE_SMOOTH) + if(m_PlayState.m_flags[SONG_FIRSTTICK] || cmd == CMD_FINETUNE_SMOOTH) SetFinetune(m_PlayState.m_nPattern, m_PlayState.m_nRow, nChn, m_PlayState, cmd == CMD_FINETUNE_SMOOTH); break; // Set Channel Global Volume case CMD_CHANNELVOLUME: - if(!m_SongFlags[SONG_FIRSTTICK]) break; + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; if (param <= 64) { chn.nGlobalVol = param; @@ -3470,7 +3470,7 @@ // Set Envelope Position case CMD_SETENVPOSITION: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.VolEnv.nEnvPosition = param; @@ -3505,7 +3505,7 @@ if(ROWINDEX row = PatternBreak(m_PlayState, nChn, static_cast<ModCommand::PARAM>(param)); row != ROWINDEX_INVALID) { m_PlayState.m_breakRow = row; - if(m_SongFlags[SONG_PATTERNLOOP]) + if(m_PlayState.m_flags[SONG_PATTERNLOOP]) { //If song is set to loop and a pattern break occurs we should stay on the same pattern. //Use nPosJump to force playback to "jump to this pattern" rather than move to next, as by default. @@ -3577,10 +3577,10 @@ } // for(...) end // Navigation Effects - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { if(HandleNextRow(m_PlayState, Order(), true)) - m_SongFlags.set(SONG_BREAKTOROW); + m_PlayState.m_flags.set(SONG_BREAKTOROW); } return true; } @@ -3624,7 +3624,7 @@ } state.m_nNextRow = state.m_breakRow; - if(!honorPatternLoop || !m_SongFlags[SONG_PATTERNLOOP]) + if(!honorPatternLoop || !m_PlayState.m_flags[SONG_PATTERNLOOP]) state.m_nNextOrder = state.m_posJump; } else if(doPatternLoop) { @@ -4101,7 +4101,7 @@ bool doTrigger = false; if(GetType() == MOD_TYPE_OKT) - doTrigger = ((chn.noteSlideParam & 0xF0) == 0x10) || m_SongFlags[SONG_FIRSTTICK]; + doTrigger = ((chn.noteSlideParam & 0xF0) == 0x10) || m_PlayState.m_flags[SONG_FIRSTTICK]; else doTrigger = !chn.isFirstTick && (--chn.noteSlideCounter == 0); @@ -4313,7 +4313,7 @@ return; } // IT Compatibility (and other trackers as well): panning disables surround (unless panning in rear channels is enabled, which is not supported by the original trackers anyway) - if (!m_SongFlags[SONG_SURROUNDPAN] && (panBits == Pan8bit || m_playBehaviour[kPanOverride])) + if (!m_PlayState.m_flags[SONG_SURROUNDPAN] && (panBits == Pan8bit || m_playBehaviour[kPanOverride])) { chn.dwFlags.reset(CHN_SURROUND); } @@ -4458,18 +4458,18 @@ { if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { param = (param & 0xF0) / 4u; nPanSlide = - (int)param; } } else if (((param & 0xF0) == 0xF0) && (param & 0x0F)) { - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { nPanSlide = (param & 0x0F) * 4u; } - } else if(!m_SongFlags[SONG_FIRSTTICK]) + } else if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0x0F) { @@ -4483,7 +4483,7 @@ } } else { - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0xF0) { @@ -4570,13 +4570,13 @@ if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { - if(m_SongFlags[SONG_FIRSTTICK]) nChnSlide = param >> 4; + if(m_PlayState.m_flags[SONG_FIRSTTICK]) nChnSlide = param >> 4; } else if (((param & 0xF0) == 0xF0) && (param & 0x0F)) { - if(m_SongFlags[SONG_FIRSTTICK]) nChnSlide = - (int)(param & 0x0F); + if(m_PlayState.m_flags[SONG_FIRSTTICK]) nChnSlide = - (int)(param & 0x0F); } else { - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0x0F) { @@ -4634,7 +4634,7 @@ // E4x: Set Vibrato WaveForm case 0x40: chn.nVibratoType = param & 0x07; break; // E5x: Set FineTune - case 0x50: if(!m_SongFlags[SONG_FIRSTTICK]) + case 0x50: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; if(GetType() & (MOD_TYPE_MOD | MOD_TYPE_DIGI | MOD_TYPE_AMF0 | MOD_TYPE_MED)) { @@ -4657,14 +4657,14 @@ break; // E6x: Pattern Loop case 0x60: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) PatternLoop(m_PlayState, nChn, param & 0x0F); break; // E7x: Set Tremolo WaveForm case 0x70: chn.nTremoloType = param & 0x07; break; // E8x: Set 4-bit Panning case 0x80: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { Panning(chn, param, Pan4bit); } @@ -4683,7 +4683,7 @@ if(GetType() == MOD_TYPE_MOD) // MOD: Invert Loop { chn.nEFxSpeed = param; - if(m_SongFlags[SONG_FIRSTTICK]) InvertLoop(chn); + if(m_PlayState.m_flags[SONG_FIRSTTICK]) InvertLoop(chn); } else // XM: Set Active Midi Macro { chn.nActiveMacro = param; @@ -4704,7 +4704,7 @@ // S1x: Set Glissando Control case 0x10: chn.dwFlags.set(CHN_GLISSANDO, param != 0); break; // S2x: Set FineTune - case 0x20: if(!m_SongFlags[SONG_FIRSTTICK]) + case 0x20: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; if(chn.HasCustomTuning()) { @@ -4761,7 +4761,7 @@ break; // S6x: Pattern Delay for x frames case 0x60: - if(m_SongFlags[SONG_FIRSTTICK] && m_PlayState.m_nTickCount == 0) + if(m_PlayState.m_flags[SONG_FIRSTTICK] && m_PlayState.m_nTickCount == 0) { // Tick delays are added up. // Scream Tracker 3 does actually not support this command. @@ -4774,7 +4774,7 @@ } break; // S7x: Envelope Control / Instrument Control - case 0x70: if(!m_SongFlags[SONG_FIRSTTICK]) break; + case 0x70: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; switch(param) { case 0: @@ -4822,7 +4822,7 @@ break; // S8x: Set 4-bit Panning case 0x80: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { Panning(chn, param, Pan4bit); } @@ -4830,7 +4830,7 @@ // S9x: Sound Control case 0x90: ExtendedChannelEffect(chn, param); break; // SAx: Set 64k Offset - case 0xA0: if(m_SongFlags[SONG_FIRSTTICK]) + case 0xA0: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nOldHiOffset = static_cast<uint8>(param); if (!m_playBehaviour[kITHighOffsetNoRetrig] && chn.rowCommand.IsNote()) @@ -4842,7 +4842,7 @@ break; // SBx: Pattern Loop case 0xB0: - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) PatternLoop(m_PlayState, nChn, param & 0x0F); break; // SCx: Note Cut @@ -4876,7 +4876,7 @@ void CSoundFile::ExtendedChannelEffect(ModChannel &chn, uint32 param) { // S9x and X9x commands (S3M/XM/IT only) - if(!m_SongFlags[SONG_FIRSTTICK]) return; + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) return; switch(param & 0x0F) { // S90: Surround Off @@ -4898,19 +4898,19 @@ break; // S9A: 2-Channels surround mode case 0x0A: - m_SongFlags.reset(SONG_SURROUNDPAN); + m_PlayState.m_flags.reset(SONG_SURROUNDPAN); break; // S9B: 4-Channels surround mode case 0x0B: - m_SongFlags.set(SONG_SURROUNDPAN); + m_PlayState.m_flags.set(SONG_SURROUNDPAN); break; // S9C: IT Filter Mode case 0x0C: - m_SongFlags.reset(SONG_MPTFILTERMODE); + m_PlayState.m_flags.reset(SONG_MPTFILTERMODE); break; // S9D: MPT Filter Mode case 0x0D: - m_SongFlags.set(SONG_MPTFILTERMODE); + m_PlayState.m_flags.set(SONG_MPTFILTERMODE); break; // S9E: Go forward case 0x0E: @@ -5465,7 +5465,7 @@ if(m_SongFlags[SONG_PT_MODE]) { - // ProTracker compatbility: PT1/2-style funky 9xx offset command + // ProTracker compatibility: PT1/2-style funky 9xx offset command // Test case: ptoffset.mod chn.position.Set(chn.prevNoteOffset); chn.prevNoteOffset += param; @@ -5580,7 +5580,7 @@ { // Buggy-like-hell FT2 Rxy retrig! // Test case: retrig.xm - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { // Here are some really stupid things FT2 does on the first tick. // Test case: RetrigTick0.xm @@ -5595,7 +5595,7 @@ } if(retrigCount >= retrigSpeed) { - if(!m_SongFlags[SONG_FIRSTTICK] || !chn.rowCommand.IsNote()) + if(!m_PlayState.m_flags[SONG_FIRSTTICK] || !chn.rowCommand.IsNote()) { doRetrig = true; retrigCount = 0; @@ -5630,7 +5630,7 @@ // FT2 bug: if a retrig (Rxy) occurs together with a volume command, the first retrig interval is increased by one tick if((param & 0x100) && (chn.rowCommand.volcmd == VOLCMD_VOLUME) && (chn.rowCommand.param & 0xF0)) realspeed++; - if(!m_SongFlags[SONG_FIRSTTICK] || (param & 0x100)) + if(!m_PlayState.m_flags[SONG_FIRSTTICK] || (param & 0x100)) { if(!realspeed) realspeed = 1; @@ -5978,13 +5978,13 @@ { // Set tempo from UI - ignore slide commands and such. m_PlayState.m_nMusicTempo = Clamp(param, specs.GetTempoMin(), specs.GetTempoMax()); - } else if(param >= minTempo && m_SongFlags[SONG_FIRSTTICK] == !m_playBehaviour[kMODTempoOnSecondTick]) + } else if(param >= minTempo && m_PlayState.m_flags[SONG_FIRSTTICK] == !m_playBehaviour[kMODTempoOnSecondTick]) { // ProTracker sets the tempo after the first tick. // Note: The case of one tick per row is handled in ProcessRow() instead. // Test case: TempoChange.mod m_PlayState.m_nMusicTempo = std::min(param, specs.GetTempoMax()); - } else if(param < minTempo && !m_SongFlags[SONG_FIRSTTICK]) + } else if(param < minTempo && !m_PlayState.m_flags[SONG_FIRSTTICK]) { // Tempo Slide TEMPO tempDiff(param.GetInt() & 0x0F, 0); @@ -6087,14 +6087,14 @@ if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { - if(m_SongFlags[SONG_FIRSTTICK]) nGlbSlide = (param >> 4) * 2; + if(m_PlayState.m_flags[SONG_FIRSTTICK]) nGlbSlide = (param >> 4) * 2; } else if (((param & 0xF0) == 0xF0) && (param & 0x0F)) { - if(m_SongFlags[SONG_FIRSTTICK]) nGlbSlide = - (int)((param & 0x0F) * 2); + if(m_PlayState.m_flags[SONG_FIRSTTICK]) nGlbSlide = - (int)((param & 0x0F) * 2); } else { - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0xF0) { @@ -6444,7 +6444,7 @@ } if(doTransition) { - if(m_SongFlags[SONG_PATTERNLOOP]) + if(m_PlayState.m_flags[SONG_PATTERNLOOP]) m_PlayState.m_nPattern = Order()[m_PlayState.m_nSeqOverride]; m_PlayState.m_nCurrentOrder = m_PlayState.m_nSeqOverride; m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/soundlib/Sndfile.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -886,7 +886,7 @@ m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag); m_visitedRows.Initialize(true); - m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED); + m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; m_PlayState.m_nMusicSpeed = Order().GetDefaultSpeed(); @@ -952,7 +952,7 @@ m_PlayState.m_nextPatStartRow = 0; } - m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED); + m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); } void CSoundFile::SuspendPlugins() @@ -1024,7 +1024,7 @@ void CSoundFile::ResetChannels() { - m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED); + m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); m_PlayState.m_nBufferCount = 0; for(auto &chn : m_PlayState.Chn) { @@ -1071,7 +1071,7 @@ { if(!Patterns.IsValidPat(nPat)) { - m_SongFlags.reset(SONG_PATTERNLOOP); + m_PlayState.m_flags.reset(SONG_PATTERNLOOP); } else { if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0; @@ -1081,7 +1081,7 @@ m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nextPatStartRow = 0; - m_SongFlags.set(SONG_PATTERNLOOP); + m_PlayState.m_flags.set(SONG_PATTERNLOOP); } m_PlayState.m_nBufferCount = 0; } @@ -1098,7 +1098,7 @@ m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nBufferCount = 0; m_PlayState.m_nextPatStartRow = 0; - m_SongFlags.reset(SONG_PATTERNLOOP); + m_PlayState.m_flags.reset(SONG_PATTERNLOOP); } Modified: trunk/OpenMPT/soundlib/Sndfile.h ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/soundlib/Sndfile.h Sun Apr 21 13:52:16 2024 (r20631) @@ -462,7 +462,7 @@ public: // for Editing #ifdef MODPLUG_TRACKER - CModDoc *m_pModDoc = nullptr; // Can be a null pointer for example when previewing samples from the treeview. + CModDoc *m_pModDoc = nullptr; // Can be a null pointer for example when previewing samples from the treeview. #endif // MODPLUG_TRACKER Enum<MODTYPE> m_nType; private: @@ -477,7 +477,7 @@ private: CHANNELINDEX m_nMixStat; public: - ROWINDEX m_nDefaultRowsPerBeat, m_nDefaultRowsPerMeasure; // default rows per beat and measure for this module + ROWINDEX m_nDefaultRowsPerBeat, m_nDefaultRowsPerMeasure; // default rows per beat and measure for this module TempoMode m_nTempoMode = TempoMode::Classic; #ifdef MODPLUG_TRACKER @@ -586,7 +586,7 @@ int32 m_lHighResRampingGlobalVolume = 0; // Global volume ramping public: - bool m_bPositionChanged = true; // Report to plugins that we jumped around in the module + FlagSet<PlayFlags> m_flags = SONG_POSITIONCHANGED; public: CHANNELINDEX ChnMix[MAX_CHANNELS]; // Index of channels in Chn to be actually mixed @@ -832,7 +832,7 @@ // A repeat count value of -1 means infinite loop void SetRepeatCount(int n) { m_nRepeatCount = n; } int GetRepeatCount() const { return m_nRepeatCount; } - bool IsPaused() const { return m_SongFlags[SONG_PAUSED | SONG_STEP]; } // Added SONG_STEP as it seems to be desirable in most cases to check for this as well. + bool IsPaused() const { return m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]; } // Added SONG_STEP as it seems to be desirable in most cases to check for this as well. void LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0); bool InitChannel(CHANNELINDEX nChn); @@ -1033,7 +1033,7 @@ void ProcessInputChannels(IAudioSource &source, std::size_t countChunk); public: samplecount_t GetTotalSampleCount() const { return m_PlayState.m_lTotalSampleCount; } - bool HasPositionChanged() { bool b = m_PlayState.m_bPositionChanged; m_PlayState.m_bPositionChanged = false; return b; } + bool HasPositionChanged() { bool b = m_PlayState.m_flags[SONG_POSITIONCHANGED]; m_PlayState.m_flags.reset(SONG_POSITIONCHANGED); return b; } bool IsRenderingToDisc() const { return m_bIsRendering; } void PrecomputeSampleLoops(bool updateChannels = false); Modified: trunk/OpenMPT/soundlib/Sndmix.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/soundlib/Sndmix.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -223,7 +223,7 @@ samplecount_t countRendered = 0; samplecount_t countToRender = count; - while(!m_SongFlags[SONG_ENDREACHED] && countToRender > 0) + while(!m_PlayState.m_flags[SONG_ENDREACHED] && countToRender > 0) { // Update Channel Data @@ -231,10 +231,10 @@ { // Last tick or fade completely processed, find out what to do next - if(m_SongFlags[SONG_FADINGSONG]) + if(m_PlayState.m_flags[SONG_FADINGSONG]) { // Song was faded out - m_SongFlags.set(SONG_ENDREACHED); + m_PlayState.m_flags.set(SONG_ENDREACHED); } else if(ReadNote()) { // Render next tick (normal progress) @@ -256,29 +256,29 @@ #ifdef MODPLUG_TRACKER if((m_nMaxOrderPosition) && (m_PlayState.m_nCurrentOrder >= m_nMaxOrderPosition)) { - m_SongFlags.set(SONG_ENDREACHED); + m_PlayState.m_flags.set(SONG_ENDREACHED); } #endif // MODPLUG_TRACKER if(IsRenderingToDisc()) { // Disable song fade when rendering or when requested in libopenmpt. - m_SongFlags.set(SONG_ENDREACHED); + m_PlayState.m_flags.set(SONG_ENDREACHED); } else { // end of song reached, fade it out if(FadeSong(FADESONGDELAY)) // sets m_nBufferCount xor returns false { // FadeSong sets m_nBufferCount here MPT_ASSERT(m_PlayState.m_nBufferCount > 0); - m_SongFlags.set(SONG_FADINGSONG); + m_PlayState.m_flags.set(SONG_FADINGSONG); } else { - m_SongFlags.set(SONG_ENDREACHED); + m_PlayState.m_flags.set(SONG_ENDREACHED); } } } } - if(m_SongFlags[SONG_ENDREACHED]) + if(m_PlayState.m_flags[SONG_ENDREACHED]) { // Mix done. @@ -375,7 +375,7 @@ // the end of the next tick. if(m_PlayState.m_nMusicSpeed == uint16_max && (m_nMixStat == 0 || m_PlayState.m_nGlobalVolume == 0) && GetType() == MOD_TYPE_XM && !m_PlayState.m_nBufferCount) { - m_SongFlags.set(SONG_ENDREACHED); + m_PlayState.m_flags.set(SONG_ENDREACHED); } } #endif // MODPLUG_TRACKER @@ -438,7 +438,7 @@ { while(++m_PlayState.m_nTickCount >= m_PlayState.TicksOnRow()) { - const auto [ignoreRow, patternTransition] = NextRow(m_PlayState, m_SongFlags[SONG_BREAKTOROW]); + const auto [ignoreRow, patternTransition] = NextRow(m_PlayState, m_PlayState.m_flags[SONG_BREAKTOROW]); #ifdef MODPLUG_TRACKER HandleRowTransitionEvents(patternTransition); @@ -457,7 +457,7 @@ #endif // MODPLUG_TRACKER // Check if pattern is valid - if(!m_SongFlags[SONG_PATTERNLOOP]) + if(!m_PlayState.m_flags[SONG_PATTERNLOOP]) { m_PlayState.m_nPattern = (m_PlayState.m_nCurrentOrder < Order().size()) ? Order()[m_PlayState.m_nCurrentOrder] : Order.GetInvalidPatIndex(); if (m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid()) m_PlayState.m_nPattern = Order.GetIgnoreIndex(); @@ -488,10 +488,10 @@ if(!(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_RESETCHANNELS)) #endif // MODPLUG_TRACKER { - m_SongFlags.set(SONG_BREAKTOROW); + m_PlayState.m_flags.set(SONG_BREAKTOROW); } - if (restartPosOverride == 0 && !m_SongFlags[SONG_BREAKTOROW]) + if (restartPosOverride == 0 && !m_PlayState.m_flags[SONG_BREAKTOROW]) { //rewbs.instroVSTi: stop all VSTi at end of song, if looping. StopAllVsti(); @@ -534,7 +534,7 @@ //Handle Repeat position m_PlayState.m_nCurrentOrder = restartPosOverride; - m_SongFlags.reset(SONG_BREAKTOROW); + m_PlayState.m_flags.reset(SONG_BREAKTOROW); //If restart pos points to +++, move along while(m_PlayState.m_nCurrentOrder < Order().size() && Order()[m_PlayState.m_nCurrentOrder] == Order.GetIgnoreIndex()) { @@ -577,7 +577,7 @@ // But: We will not mark the row as modified if the song is not in loop mode but // the pattern loop (editor flag, not to be confused with the pattern loop effect) // flag is set - because in that case, the module would stop after the first pattern loop... - const bool overrideLoopCheck = (m_nRepeatCount != -1) && m_SongFlags[SONG_PATTERNLOOP]; + const bool overrideLoopCheck = (m_nRepeatCount != -1) && m_PlayState.m_flags[SONG_PATTERNLOOP]; if(!overrideLoopCheck && m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow)) { if(m_nRepeatCount) @@ -663,7 +663,7 @@ } } - SetupNextRow(m_PlayState, m_SongFlags[SONG_PATTERNLOOP]); + SetupNextRow(m_PlayState, m_PlayState.m_flags[SONG_PATTERNLOOP]); // Reset channel values ModCommand *m = Patterns[m_PlayState.m_nPattern].GetpModCommand(m_PlayState.m_nRow, 0); @@ -735,17 +735,17 @@ #ifdef MODPLUG_TRACKER if (m_PlayState.m_nTickCount >= m_PlayState.TicksOnRow() - 1) { - if(m_SongFlags[SONG_STEP]) + if(m_PlayState.m_flags[SONG_STEP]) { - m_SongFlags.reset(SONG_STEP); - m_SongFlags.set(SONG_PAUSED); + m_PlayState.m_flags.reset(SONG_STEP); + m_PlayState.m_flags.set(SONG_PAUSED); } } #endif // MODPLUG_TRACKER if (m_PlayState.m_nTickCount) { - m_SongFlags.reset(SONG_FIRSTTICK); + m_PlayState.m_flags.reset(SONG_FIRSTTICK); if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) && (GetType() != MOD_TYPE_MOD || m_SongFlags[SONG_PT_MODE]) // Fix infinite loop in "GamerMan " by MrGamer, which was made with FT2 && m_PlayState.m_nTickCount < m_PlayState.TicksOnRow()) @@ -754,13 +754,13 @@ // Test cases: PatternDelaysRetrig.it, PatternDelaysRetrig.s3m, PatternDelaysRetrig.xm, PatternDelaysRetrig.mod if(!(m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay))) { - m_SongFlags.set(SONG_FIRSTTICK); + m_PlayState.m_flags.set(SONG_FIRSTTICK); } } } else { - m_SongFlags.set(SONG_FIRSTTICK); - m_SongFlags.reset(SONG_BREAKTOROW); + m_PlayState.m_flags.set(SONG_FIRSTTICK); + m_PlayState.m_flags.reset(SONG_BREAKTOROW); } // Update Effects @@ -907,7 +907,7 @@ { if (chn.dwFlags[CHN_TREMOLO]) { - if(m_SongFlags.test_all(SONG_FIRSTTICK | SONG_PT_MODE)) + if(m_SongFlags[SONG_PT_MODE] && m_PlayState.m_flags[SONG_FIRSTTICK]) { // ProTracker doesn't apply tremolo nor advance on the first tick. // Test case: VibratoReset.mod @@ -923,12 +923,12 @@ int delta = GetVibratoDelta(chn.nTremoloType, chn.nTremoloPos); if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2MODTremoloRampWaveform]) { - // FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copypaste bug) + // FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copy-paste bug) // Test case: TremoloWaveforms.xm, TremoloVibrato.xm uint8 ramp = (chn.nTremoloPos * 4u) & 0x7F; - // Volume-colum vibrato gets executed first in FT2, so we may need to advance the vibrato position first + // Volume-column vibrato gets executed first in FT2, so we may need to advance the vibrato position first uint32 vibPos = chn.nVibratoPos; - if(!m_SongFlags[SONG_FIRSTTICK] && chn.dwFlags[CHN_VIBRATO]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK] && chn.dwFlags[CHN_VIBRATO]) vibPos += chn.nVibratoSpeed; if((vibPos & 0x3F) >= 32) ramp ^= 0x7F; @@ -946,7 +946,7 @@ vol -= (vol * chn.nTremoloDepth * (64 - delta)) / (128 * 64); } } - if(!m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])) + if(!m_PlayState.m_flags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])) { // IT compatibility: IT has its own, more precise tables if(m_playBehaviour[kITVibratoTremoloPanbrello]) @@ -968,7 +968,7 @@ // Test case: Tremor.xm if(chn.nTremorCount & 0x80) { - if(!m_SongFlags[SONG_FIRSTTICK] && chn.nCommand == CMD_TREMOR) + if(!m_PlayState.m_flags[SONG_FIRSTTICK] && chn.nCommand == CMD_TREMOR) { chn.nTremorCount &= ~0x20; if(chn.nTremorCount == 0x80) @@ -1026,7 +1026,7 @@ chn.nTremorCount = tremcount + 1; } else { - if(m_SongFlags[SONG_FIRSTTICK]) + if(m_PlayState.m_flags[SONG_FIRSTTICK]) { // tremcount is only 0 on the first tremor tick after triggering a note. if(tremcount > 0) @@ -1510,7 +1510,7 @@ chn.m_ReCalculateFreqOnFirstTick = true; } else { - if(GetType() == MOD_TYPE_MT2 && m_SongFlags[SONG_FIRSTTICK]) + if(GetType() == MOD_TYPE_MT2 && m_PlayState.m_flags[SONG_FIRSTTICK]) { // MT2 resets any previous portamento when an arpeggio occurs. chn.nPeriod = period = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); @@ -1539,7 +1539,7 @@ } else if(m_playBehaviour[kFT2Arpeggio]) { // FastTracker 2: Swedish tracker logic (TM) arpeggio - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { // Arpeggio is added on top of current note, but cannot do it the IT way because of // the behaviour in ArpeggioClamp.xm. @@ -1660,7 +1660,7 @@ if(chn.dwFlags[CHN_VIBRATO]) { - const bool advancePosition = !m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !(m_SongFlags[SONG_ITOLDEFFECTS])); + const bool advancePosition = !m_PlayState.m_flags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !(m_SongFlags[SONG_ITOLDEFFECTS])); if(GetType() == MOD_TYPE_669) { @@ -1691,7 +1691,7 @@ } else { // Original behaviour - if(m_SongFlags.test_all(SONG_FIRSTTICK | SONG_PT_MODE) || ((GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM)) && m_SongFlags[SONG_FIRSTTICK])) + if((m_SongFlags[SONG_PT_MODE] || (GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM))) && m_PlayState.m_flags[SONG_FIRSTTICK]) { // ProTracker doesn't apply vibrato nor advance on the first tick. // Test case: VibratoReset.mod @@ -2030,7 +2030,7 @@ if(!chn.triggerNote) return cutoff; - bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE]; + bool useFilter = !m_PlayState.m_flags[SONG_MPTFILTERMODE]; if(const ModInstrument *pIns = chn.pModInstrument; pIns != nullptr) { if(pIns->IsResonanceEnabled()) @@ -2100,7 +2100,7 @@ { #ifdef MODPLUG_TRACKER // Checking end of row ? - if(m_SongFlags[SONG_PAUSED]) + if(m_PlayState.m_flags[SONG_PAUSED]) { m_PlayState.m_nTickCount = 0; if (!m_PlayState.m_nMusicSpeed) m_PlayState.m_nMusicSpeed = 6; @@ -2284,7 +2284,7 @@ // When glissando mode is set to semitones, clamp to the next halftone. if((chn.dwFlags & (CHN_GLISSANDO | CHN_PORTAMENTO)) == (CHN_GLISSANDO | CHN_PORTAMENTO) - && (!m_SongFlags[SONG_PT_MODE] || (chn.rowCommand.IsPortamento() && !m_SongFlags[SONG_FIRSTTICK]))) + && (!m_SongFlags[SONG_PT_MODE] || (chn.rowCommand.IsPortamento() && !m_PlayState.m_flags[SONG_FIRSTTICK]))) { if(period != chn.cachedPeriod) { @@ -2322,7 +2322,7 @@ // IT Compatibility: Ensure that there is no pan swing, panbrello, panning envelopes, etc. applied on surround channels. // Test case: surround-pan.it - if(chn.dwFlags[CHN_SURROUND] && !m_SongFlags[SONG_SURROUNDPAN] && m_playBehaviour[kITNoSurroundPan]) + if(chn.dwFlags[CHN_SURROUND] && !m_PlayState.m_flags[SONG_SURROUNDPAN] && m_playBehaviour[kITNoSurroundPan]) { chn.nRealPan = 128; } @@ -2351,7 +2351,7 @@ // XM Compatibility: Vibrato should be advanced twice (but not added up) if both volume-column and effect column vibrato is present. // Effect column vibrato parameter has precedence if non-zero. // Test case: VibratoDouble.xm - if(!m_SongFlags[SONG_FIRSTTICK]) + if(!m_PlayState.m_flags[SONG_FIRSTTICK]) chn.nVibratoPos += chn.nVibratoSpeed; } else if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) { @@ -2615,7 +2615,7 @@ //ProcessMIDIMacro(m_PlayState, nChn, false, m_MidiCfg.Global[MIDIOUT_PAN]); //ProcessMIDIMacro(m_PlayState, nChn, false, m_MidiCfg.Global[MIDIOUT_VOLUME]); - if((chn.rowCommand.command == CMD_MIDI && m_SongFlags[SONG_FIRSTTICK]) || chn.rowCommand.command == CMD_SMOOTHMIDI) + if((chn.rowCommand.command == CMD_MIDI && m_PlayState.m_flags[SONG_FIRSTTICK]) || chn.rowCommand.command == CMD_SMOOTHMIDI) { if(chn.rowCommand.param < 0x80) ProcessMIDIMacro(m_PlayState, nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.SFx[chn.nActiveMacro], chn.rowCommand.param); Modified: trunk/OpenMPT/test/test.cpp ============================================================================== --- trunk/OpenMPT/test/test.cpp Sun Apr 21 12:59:02 2024 (r20630) +++ trunk/OpenMPT/test/test.cpp Sun Apr 21 13:52:16 2024 (r20631) @@ -2701,7 +2701,7 @@ VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 128); VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 42); VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 23); - VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_LINEARSLIDES | SONG_EXFILTERRANGE); + VERIFY_EQUAL_NONCONT(sndFile.m_SongFlags, SONG_LINEARSLIDES | SONG_EXFILTERRANGE); VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[MSF_COMPATIBLE_PLAY], true); VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMIDICCBugEmulation], false); VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMPTOldSwingBehaviour], false); @@ -2899,7 +2899,7 @@ VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 128); VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 42); VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 23); - VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS); + VERIFY_EQUAL_NONCONT(sndFile.m_SongFlags, SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS); VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[MSF_COMPATIBLE_PLAY], true); VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMIDICCBugEmulation], false); VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMPTOldSwingBehaviour], false); @@ -3278,7 +3278,7 @@ VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 32 * 4); VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 36); VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 16); - VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_FASTVOLSLIDES); + VERIFY_EQUAL_NONCONT(sndFile.m_SongFlags, SONG_FASTVOLSLIDES); VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), MixLevels::Compatible); VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, TempoMode::Classic); VERIFY_EQUAL_NONCONT(sndFile.m_dwLastSavedWithVersion, resaved ? Version::Current() : MPT_V("1.27.00.00")); @@ -3404,7 +3404,7 @@ { // Global Variables VERIFY_EQUAL_NONCONT(sndFile.GetTitle(), "MOD_Test___________X"); - VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_PT_MODE | SONG_AMIGALIMITS | SONG_ISAMIGA); + VERIFY_EQUAL_NONCONT(sndFile.m_SongFlags, SONG_PT_MODE | SONG_AMIGALIMITS | SONG_ISAMIGA); VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), MixLevels::Compatible); VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, TempoMode::Classic); VERIFY_EQUAL_NONCONT(sndFile.GetNumChannels(), 4); |
From: <sv...@op...> - 2024-04-21 10:59:14
|
Author: manx Date: Sun Apr 21 12:59:02 2024 New Revision: 20630 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20630 Log: Merged revision(s) 20629 from branches/OpenMPT-1.30: Merged revision(s) 20627 from trunk/OpenMPT: [Mod] build: cppcheck: Enable --check-level=exhaustive. The performance cost is around ~10%. ........ ........ Modified: branches/OpenMPT-1.29/ (props changed) branches/OpenMPT-1.29/Makefile branches/OpenMPT-1.29/build/auto/cppcheck_openmpt.sh Modified: branches/OpenMPT-1.29/Makefile ============================================================================== --- branches/OpenMPT-1.29/Makefile Sun Apr 21 12:55:23 2024 (r20629) +++ branches/OpenMPT-1.29/Makefile Sun Apr 21 12:59:02 2024 (r20630) @@ -738,6 +738,7 @@ CPPCHECK_FLAGS += --std=c99 --std=c++17 CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' +CPPCHECL_FLAGS += --check-level=exhaustive CPPCHECK_FLAGS += --suppress=missingIncludeSystem CPPCHECK_FLAGS += --suppress=uninitMemberVar Modified: branches/OpenMPT-1.29/build/auto/cppcheck_openmpt.sh ============================================================================== --- branches/OpenMPT-1.29/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:55:23 2024 (r20629) +++ branches/OpenMPT-1.29/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:59:02 2024 (r20630) @@ -32,6 +32,6 @@ echo "Platform: $CPPCHECK_PLATFORM" echo "Checking config ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=mfc.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=mfc.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive --check --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES echo "Checking C++ ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=mfc.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=mfc.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive --check $CPPCHECK_FILES |
From: <sv...@op...> - 2024-04-21 10:55:38
|
Author: manx Date: Sun Apr 21 12:55:23 2024 New Revision: 20629 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20629 Log: Merged revision(s) 20627 from trunk/OpenMPT: [Mod] build: cppcheck: Enable --check-level=exhaustive. The performance cost is around ~10%. ........ Modified: branches/OpenMPT-1.30/ (props changed) branches/OpenMPT-1.30/Makefile branches/OpenMPT-1.30/build/auto/cppcheck_openmpt.sh Modified: branches/OpenMPT-1.30/Makefile ============================================================================== --- branches/OpenMPT-1.30/Makefile Sun Apr 21 12:53:03 2024 (r20628) +++ branches/OpenMPT-1.30/Makefile Sun Apr 21 12:55:23 2024 (r20629) @@ -787,6 +787,7 @@ CPPCHECK_FLAGS += --std=c99 --std=c++17 CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' +CPPCHECL_FLAGS += --check-level=exhaustive CPPCHECK_FLAGS += --suppress=missingIncludeSystem CPPCHECK_FLAGS += --suppress=uninitMemberVar Modified: branches/OpenMPT-1.30/build/auto/cppcheck_openmpt.sh ============================================================================== --- branches/OpenMPT-1.30/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:53:03 2024 (r20628) +++ branches/OpenMPT-1.30/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:55:23 2024 (r20629) @@ -32,6 +32,6 @@ echo "Platform: $CPPCHECK_PLATFORM" echo "Checking config ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES echo "Checking C++ ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c99 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive $CPPCHECK_FILES |
From: <sv...@op...> - 2024-04-21 10:53:15
|
Author: manx Date: Sun Apr 21 12:53:03 2024 New Revision: 20628 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20628 Log: Merged revision(s) 20627 from trunk/OpenMPT: [Mod] build: cppcheck: Enable --check-level=exhaustive. The performance cost is around ~10%. ........ Modified: branches/OpenMPT-1.31/ (props changed) branches/OpenMPT-1.31/Makefile branches/OpenMPT-1.31/build/auto/cppcheck_openmpt.sh Modified: branches/OpenMPT-1.31/Makefile ============================================================================== --- branches/OpenMPT-1.31/Makefile Sun Apr 21 12:52:12 2024 (r20627) +++ branches/OpenMPT-1.31/Makefile Sun Apr 21 12:53:03 2024 (r20628) @@ -999,6 +999,7 @@ CPPCHECK_FLAGS += --std=c11 --std=c++17 CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' +CPPCHECL_FLAGS += --check-level=exhaustive CPPCHECK_FLAGS += --suppress=missingIncludeSystem CPPCHECK_FLAGS += --suppress=uninitMemberVar Modified: branches/OpenMPT-1.31/build/auto/cppcheck_openmpt.sh ============================================================================== --- branches/OpenMPT-1.31/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:52:12 2024 (r20627) +++ branches/OpenMPT-1.31/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:53:03 2024 (r20628) @@ -32,6 +32,6 @@ echo "Platform: $CPPCHECK_PLATFORM" echo "Checking config ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES echo "Checking C++ ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive $CPPCHECK_FILES |
From: <sv...@op...> - 2024-04-21 10:52:20
|
Author: manx Date: Sun Apr 21 12:52:12 2024 New Revision: 20627 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20627 Log: [Mod] build: cppcheck: Enable --check-level=exhaustive. The performance cost is around ~10%. Modified: trunk/OpenMPT/Makefile trunk/OpenMPT/build/auto/cppcheck_openmpt.sh Modified: trunk/OpenMPT/Makefile ============================================================================== --- trunk/OpenMPT/Makefile Sun Apr 21 10:21:10 2024 (r20626) +++ trunk/OpenMPT/Makefile Sun Apr 21 12:52:12 2024 (r20627) @@ -1069,6 +1069,7 @@ CPPCHECK_FLAGS += --std=c11 --std=c++17 CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' +CPPCHECL_FLAGS += --check-level=exhaustive CPPCHECK_FLAGS += --suppress=missingIncludeSystem CPPCHECK_FLAGS += --suppress=uninitMemberVar Modified: trunk/OpenMPT/build/auto/cppcheck_openmpt.sh ============================================================================== --- trunk/OpenMPT/build/auto/cppcheck_openmpt.sh Sun Apr 21 10:21:10 2024 (r20626) +++ trunk/OpenMPT/build/auto/cppcheck_openmpt.sh Sun Apr 21 12:52:12 2024 (r20627) @@ -32,6 +32,6 @@ echo "Platform: $CPPCHECK_PLATFORM" echo "Checking config ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive --check-config --suppress=unmatchedSuppression $CPPCHECK_FILES echo "Checking C++ ..." -cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES $CPPCHECK_FILES +cppcheck -j $NPROC -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $CPPCHECK_PLATFORM --std=c11 --std=c++17 --library=windows.cfg --library=microsoft_atl.cfg --library=mfc.cfg --library=build/cppcheck/mfc-extras.cfg --library=build/cppcheck/nlohmann-json.cfg --suppressions-list=build/cppcheck/nlohmann-json.suppressions.txt --suppressions-list=build/cppcheck/r8brain.suppressions.txt --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' --suppress=missingIncludeSystem --suppress=uninitMemberVar $CPPCHECK_OPTIONS $CPPCHECK_DEFINES $CPPCHECK_INCLUDES --check-level=exhaustive $CPPCHECK_FILES |
From: <sv...@op...> - 2024-04-21 08:21:22
|
Author: manx Date: Sun Apr 21 10:21:10 2024 New Revision: 20626 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20626 Log: Merged revision(s) 20625 from trunk/OpenMPT: [Imp] build: Android: Enable support for non-4kiB page sizes for NDK r27. See <https://developer.android.com/guide/practices/page-sizes>. ........ Modified: branches/OpenMPT-1.31/ (props changed) branches/OpenMPT-1.31/build/android_ndk/Application.mk Modified: branches/OpenMPT-1.31/build/android_ndk/Application.mk ============================================================================== --- branches/OpenMPT-1.31/build/android_ndk/Application.mk Sun Apr 21 10:20:43 2024 (r20625) +++ branches/OpenMPT-1.31/build/android_ndk/Application.mk Sun Apr 21 10:21:10 2024 (r20626) @@ -3,3 +3,5 @@ APP_CPPFLAGS := -std=c++17 -fexceptions -frtti APP_LDFLAGS := APP_STL := c++_shared + +APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true |
From: <sv...@op...> - 2024-04-21 08:20:55
|
Author: manx Date: Sun Apr 21 10:20:43 2024 New Revision: 20625 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20625 Log: [Imp] build: Android: Enable support for non-4kiB page sizes for NDK r27. See <https://developer.android.com/guide/practices/page-sizes>. Modified: trunk/OpenMPT/build/android_ndk/Application.mk Modified: trunk/OpenMPT/build/android_ndk/Application.mk ============================================================================== --- trunk/OpenMPT/build/android_ndk/Application.mk Sat Apr 20 22:16:42 2024 (r20624) +++ trunk/OpenMPT/build/android_ndk/Application.mk Sun Apr 21 10:20:43 2024 (r20625) @@ -3,3 +3,5 @@ APP_CPPFLAGS := -std=c++17 -fexceptions -frtti APP_LDFLAGS := APP_STL := c++_shared + +APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true |
From: <sv...@op...> - 2024-04-20 20:16:57
|
Author: sagamusix Date: Sat Apr 20 22:16:42 2024 New Revision: 20624 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20624 Log: [Imp] NatVis: Better visualization of packed little-endian floats. For big-endian floats it doesn't really seem to be possible to achieve the same. Modified: trunk/OpenMPT/build/vs/debug/openmpt.natvis Modified: trunk/OpenMPT/build/vs/debug/openmpt.natvis ============================================================================== --- trunk/OpenMPT/build/vs/debug/openmpt.natvis Sat Apr 20 21:27:18 2024 (r20623) +++ trunk/OpenMPT/build/vs/debug/openmpt.natvis Sat Apr 20 22:16:42 2024 (r20624) @@ -130,4 +130,9 @@ <Type Name="mpt::mptx::packed<unsigned char,1,unsigned char>"> <DisplayString>{(uint8)data[0]}</DisplayString> </Type> + + <!-- Floating-point Little-Endian --> + <Type Name="mpt::mptx::IEEE754binary32Emulated<3,2,1,0>"> + <DisplayString>{*(float*)&bytes}</DisplayString> + </Type> </AutoVisualizer> |
From: <sv...@op...> - 2024-04-20 19:27:30
|
Author: sagamusix Date: Sat Apr 20 21:27:18 2024 New Revision: 20623 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20623 Log: [Mod] IT: ChibiTracker's mixer is about half as loud as ours. Halve the sample pre-amp when ChibiTracker-made IT is detected. Modified: trunk/OpenMPT/soundlib/Load_it.cpp Modified: trunk/OpenMPT/soundlib/Load_it.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp Sat Apr 20 18:15:57 2024 (r20622) +++ trunk/OpenMPT/soundlib/Load_it.cpp Sat Apr 20 21:27:18 2024 (r20623) @@ -1209,6 +1209,7 @@ { madeWithTracker = U_("ChibiTracker"); m_playBehaviour.reset(kITShortSampleRetrig); + m_nSamplePreAmp /= 2; } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && fileHeader.special <= 1 && fileHeader.pwd == 0 && fileHeader.reserved == 0 && (fileHeader.flags & (ITFileHeader::vol0Optimisations | ITFileHeader::instrumentMode | ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig | ITFileHeader::extendedFilterRange)) == ITFileHeader::instrumentMode && m_nSamples > 0 && (Samples[1].filename == "XXXXXXXX.YYY")) |
From: <sv...@op...> - 2024-04-20 16:16:10
|
Author: sagamusix Date: Sat Apr 20 18:15:57 2024 New Revision: 20622 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20622 Log: [Imp] IT: Reduce number of FileReader calls during initial pattern scan. Modified: trunk/OpenMPT/soundlib/Load_it.cpp Modified: trunk/OpenMPT/soundlib/Load_it.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp Sat Apr 20 18:12:47 2024 (r20621) +++ trunk/OpenMPT/soundlib/Load_it.cpp Sat Apr 20 18:15:57 2024 (r20622) @@ -927,31 +927,22 @@ chnMask.resize(ch + 1, 0); } - if(b & IT_bitmask_patternChanEnabled_c) // 0x80 check if the upper bit is enabled. + if(b & IT_bitmask_patternChanEnabled_c) // 0x80 check if the upper bit is enabled. { - chnMask[ch] = patternData.ReadUint8(); // set the channel mask for this channel. + chnMask[ch] = patternData.ReadUint8(); // set the channel mask for this channel. } // Channel used - if(chnMask[ch] & 0x0F) // if this channel is used set m_nChannels + if(chnMask[ch] & 0x0F) // if this channel is used set m_nChannels { if(ch >= GetNumChannels() && ch < MAX_BASECHANNELS) { m_nChannels = ch + 1; } + + // Skip a number of bytes depending on note, instrument, volume, effect being present. + static constexpr uint8 maskToSkips[] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5}; + patternData.Skip(maskToSkips[chnMask[ch] & 0x0F]); } - // Now we actually update the pattern-row entry the note,instrument etc. - // Note - if(chnMask[ch] & 1) - patternData.Skip(1); - // Instrument - if(chnMask[ch] & 2) - patternData.Skip(1); - // Volume - if(chnMask[ch] & 4) - patternData.Skip(1); - // Effect - if(chnMask[ch] & 8) - patternData.Skip(2); } lastSampleOffset = std::max(lastSampleOffset, file.GetPosition()); } |
From: <sv...@op...> - 2024-04-20 16:12:54
|
Author: sagamusix Date: Sat Apr 20 18:12:47 2024 New Revision: 20621 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20621 Log: [Mod] GMC: Add missing madeWithTracker information. Modified: trunk/OpenMPT/soundlib/Load_gmc.cpp Modified: trunk/OpenMPT/soundlib/Load_gmc.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_gmc.cpp Fri Apr 19 18:33:40 2024 (r20620) +++ trunk/OpenMPT/soundlib/Load_gmc.cpp Sat Apr 20 18:12:47 2024 (r20621) @@ -237,6 +237,7 @@ } } + m_modFormat.madeWithTracker = U_("Game Music Creator"); m_modFormat.formatName = U_("Game Music Creator"); m_modFormat.type = UL_("GMC"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; // No strings in this format... |
From: <sv...@op...> - 2024-04-19 20:12:34
|
Author: sagamusix Date: Fri Apr 19 18:33:40 2024 New Revision: 20620 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20620 Log: [Var] Update fuzzer dictionary. Modified: trunk/OpenMPT/contrib/fuzzing/all_formats.dict Modified: trunk/OpenMPT/contrib/fuzzing/all_formats.dict ============================================================================== --- trunk/OpenMPT/contrib/fuzzing/all_formats.dict Thu Apr 18 23:25:20 2024 (r20619) +++ trunk/OpenMPT/contrib/fuzzing/all_formats.dict Fri Apr 19 18:33:40 2024 (r20620) @@ -354,3 +354,5 @@ puma="patt" puma="inst" puma="insf" + +kris="KRIS" \ No newline at end of file |
From: <sv...@op...> - 2024-04-18 21:25:28
|
Author: sagamusix Date: Thu Apr 18 23:25:20 2024 New Revision: 20619 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20619 Log: [Ref] Silence warnings. Modified: trunk/OpenMPT/soundlib/Load_mod.cpp Modified: trunk/OpenMPT/soundlib/Load_mod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp Thu Apr 18 21:11:34 2024 (r20618) +++ trunk/OpenMPT/soundlib/Load_mod.cpp Thu Apr 18 23:25:20 2024 (r20619) @@ -2211,7 +2211,7 @@ std::array<std::array<uint8, 2>, 128 * 4> tracks; if(!file.ReadArray(tracks)) return false; - uint16 tracksOffset = 1984; + uint32 tracksOffset = 1984; InitializeGlobals(MOD_TYPE_MOD); @@ -2241,7 +2241,7 @@ if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) return false; } - tracksOffset += numSynthWaveforms * 64; + tracksOffset += numSynthWaveforms * 64u; if(loadFlags == onlyVerifyHeader) return true; |
From: <sv...@op...> - 2024-04-18 19:11:47
|
Author: sagamusix Date: Thu Apr 18 21:11:34 2024 New Revision: 20618 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20618 Log: [New] Can now load ChipTracker modules, another SoundTracker clone using a track-based approach. As it shares the typical MOD sample structures, it is also placed in Load_mod.cpp. Modified: trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Tables.cpp Modified: trunk/OpenMPT/soundlib/Load_mod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp Wed Apr 17 20:48:34 2024 (r20617) +++ trunk/OpenMPT/soundlib/Load_mod.cpp Thu Apr 18 21:11:34 2024 (r20618) @@ -1,7 +1,7 @@ /* * Load_mod.cpp * ------------ - * Purpose: MOD / NST (ProTracker / NoiseTracker), M15 / STK (Ultimate Soundtracker / Soundtracker) and ST26 (SoundTracker 2.6 / Ice Tracker) module loader / saver + * Purpose: MOD / NST (ProTracker / NoiseTracker), M15 / STK (Ultimate Soundtracker / Soundtracker), ST26 (SoundTracker 2.6 / Ice Tracker) and ChipTracker module loader / saver * Notes : "2000 LOC for processing MOD files?!" you say? Well, this file also contains loaders for some formats that are almost identical to MOD, and extensive * heuristics for more or less broken MOD files and files saved with tons of different trackers, to allow for the most optimal playback. * Authors: Olivier Lapicque @@ -2170,6 +2170,154 @@ } +CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderKRIS(MemoryFileReader file, const uint64 *pfilesize) +{ + if(!file.CanRead(952 + 4)) + return ProbeWantMoreData; + + file.Seek(952); + if(!file.ReadMagic("KRIS")) + return ProbeFailure; + + const auto [numOrders, restartPos] = file.ReadArray<uint8, 2>(); + if(numOrders > 128 || restartPos > 127) + return ProbeFailure; + + file.Seek(22); + uint32 invalidBytes = 0; + for(SAMPLEINDEX smp = 1; smp <= 31; smp++) + { + MODSampleHeader sampleHeader; + file.ReadStruct(sampleHeader); + invalidBytes += sampleHeader.GetInvalidByteScore(); + if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) + return ProbeFailure; + } + + MPT_UNREFERENCED_PARAMETER(pfilesize); + return ProbeSuccess; +} + + +bool CSoundFile::ReadKRIS(FileReader &file, ModLoadingFlags loadFlags) +{ + if (!file.Seek(952) || !file.ReadMagic("KRIS")) + return false; + + const auto [numOrders, restartPos] = file.ReadArray<uint8, 2>(); + if(numOrders > 128 || restartPos > 127) + return false; + + std::array<std::array<uint8, 2>, 128 * 4> tracks; + if(!file.ReadArray(tracks)) + return false; + uint16 tracksOffset = 1984; + + InitializeGlobals(MOD_TYPE_MOD); + + file.Seek(0); + file.ReadString<mpt::String::spacePadded>(m_songName, 22); + + m_nSamples = 31; + uint32 invalidBytes = 0; + uint8 numSynthWaveforms = 0; + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + { + MODSampleHeader sampleHeader; + file.ReadStruct(sampleHeader); + if(sampleHeader.name[0] != 0) + { + invalidBytes += ReadSample(sampleHeader, Samples[smp], m_szNames[smp], true); + } else + { + // Unfinished feature. Synth parameters are stored in the module, but loading and saving of synth waveforms + // (which I'd assume the extra space before the track data is reserved for) is completely absent, making the feature useless. + Samples[smp].Initialize(MOD_TYPE_MOD); + m_szNames[smp] = "Synthetic"; + const uint8 maxWaveform = std::max({ sampleHeader.name[1], sampleHeader.name[5], sampleHeader.name[10], sampleHeader.name[19] }); + if(maxWaveform) + numSynthWaveforms = std::max(numSynthWaveforms, static_cast<uint8>(maxWaveform + 1)); + } + if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) + return false; + } + tracksOffset += numSynthWaveforms * 64; + + if(loadFlags == onlyVerifyHeader) + return true; + + m_nChannels = 4; + SetupMODPanning(true); + Order().SetDefaultSpeed(6); + Order().SetDefaultTempoInt(125); + Order().SetRestartPos(restartPos); + m_nMinPeriod = 113 * 4; + m_nMaxPeriod = 856 * 4; + m_nSamplePreAmp = 64; + m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED); + m_playBehaviour.set(kMODIgnorePanning); + m_playBehaviour.set(kMODSampleSwap); + + Order().resize(numOrders); + if(loadFlags & loadPatternData) + Patterns.ResizeArray(numOrders); + for(PATTERNINDEX pat = 0; pat < numOrders; pat++) + { + if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) + break; + Order()[pat] = pat; + for(CHANNELINDEX chn = 0; chn < 4; chn++) + { + const uint8 track = tracks[pat * 4u + chn][0]; + const int8 transpose = tracks[pat * 4u + chn][1]; + if(!file.Seek(tracksOffset + track * 256u)) + return false; + ModCommand *m = Patterns[pat].GetpModCommand(0, chn); + for(ROWINDEX row = 0; row < 64; row++, m += 4) + { + const auto data = file.ReadArray<uint8, 4>(); + if(data[0] & 1) + return false; + if(data[0] >= 0x18 && data[0] <= 0x9E) + m->note = static_cast<ModCommand::NOTE>(Clamp(NOTE_MIDDLEC - 36 + (data[0] - 0x18) / 2 + transpose, NOTE_MIDDLEC - 12, NOTE_MIDDLEC + 23)); + else if(data[0] != 0xA8) + return false; + if(data[2] >> 4) + return false; + m->instr = data[1]; + ConvertModCommand(*m, data[2] & 0x0F, data[3]); + } + } + } + + m_modFormat.formatName = U_("ChipTracker"); + m_modFormat.type = U_("mod"); + m_modFormat.madeWithTracker = U_("ChipTracker"); + m_modFormat.charset = mpt::Charset::Amiga_no_C1; + + if(loadFlags & loadSampleData) + { + uint8 maxTrack = 0; + for(uint32 ord = 0; ord < numOrders * 4u; ord++) + { + maxTrack = std::max(tracks[ord][0], maxTrack); + } + file.Seek(tracksOffset + (maxTrack + 1u) * 256u); + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + if(Samples[smp].nLength) + { + SampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(Samples[smp], file); + } + } + + return true; +} + struct PT36Header { Modified: trunk/OpenMPT/soundlib/Sndfile.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp Wed Apr 17 20:48:34 2024 (r20617) +++ trunk/OpenMPT/soundlib/Sndfile.cpp Thu Apr 18 21:11:34 2024 (r20618) @@ -310,6 +310,7 @@ MPT_DECLARE_FORMAT(STX), MPT_DECLARE_FORMAT(MOD), MPT_DECLARE_FORMAT(ICE), + MPT_DECLARE_FORMAT(KRIS), MPT_DECLARE_FORMAT(669), MPT_DECLARE_FORMAT(667), MPT_DECLARE_FORMAT(C67), Modified: trunk/OpenMPT/soundlib/Sndfile.h ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h Wed Apr 17 20:48:34 2024 (r20617) +++ trunk/OpenMPT/soundlib/Sndfile.h Thu Apr 18 21:11:34 2024 (r20618) @@ -875,6 +875,7 @@ static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize); + static ProbeResult ProbeFileHeaderKRIS(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMUS_KM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize); @@ -931,6 +932,7 @@ bool ReadIT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadITP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadJ2B(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadKRIS(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMUS_KM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); Modified: trunk/OpenMPT/soundlib/Tables.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Tables.cpp Wed Apr 17 20:48:34 2024 (r20617) +++ trunk/OpenMPT/soundlib/Tables.cpp Thu Apr 18 21:11:34 2024 (r20618) @@ -51,6 +51,7 @@ { { UL_("OpenMPT"), "mptm" }, { UL_("ProTracker"), "mod" }, + { UL_("ChipTracker"), "mod" }, { UL_("Scream Tracker 3"), "s3m" }, { UL_("FastTracker 2"), "xm" }, { UL_("Impulse Tracker"), "it" }, |
From: <sv...@op...> - 2024-04-17 18:48:43
|
Author: sagamusix Date: Wed Apr 17 20:48:34 2024 New Revision: 20617 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20617 Log: [Mod] ICE: Don't reset CSoundFile before we have even verified the magic bytes. Don't load patterns if we weren't asked to. Modified: trunk/OpenMPT/soundlib/Load_mod.cpp Modified: trunk/OpenMPT/soundlib/Load_mod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp Wed Apr 17 20:26:48 2024 (r20616) +++ trunk/OpenMPT/soundlib/Load_mod.cpp Wed Apr 17 20:48:34 2024 (r20617) @@ -1977,44 +1977,35 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(1464 + 4)) - { return ProbeWantMoreData; - } + file.Seek(1464); char magic[4]; file.ReadArray(magic); if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10")) - { return ProbeFailure; - } + file.Seek(20); uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; - if(!file.ReadStruct(sampleHeader)) - { - return ProbeWantMoreData; - } + file.ReadStruct(sampleHeader); invalidBytes += sampleHeader.GetInvalidByteScore(); - } - if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) - { - return ProbeFailure; + if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) + return ProbeFailure; } const auto [numOrders, numTracks] = file.ReadArray<uint8, 2>(); if(numOrders > 128) { return ProbeFailure; } - uint8 tracks[128 * 4]; + std::array<uint8, 128 * 4> tracks; file.ReadArray(tracks); for(auto track : tracks) { if(track > numTracks) - { return ProbeFailure; - } } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; @@ -2032,19 +2023,16 @@ return false; } - InitializeGlobals(MOD_TYPE_MOD); - m_playBehaviour.reset(kMODOneShotLoops); - m_playBehaviour.set(kMODIgnorePanning); - m_playBehaviour.set(kMODSampleSwap); // untested - if(IsMagic(magic, "MTN\0")) { + InitializeGlobals(MOD_TYPE_MOD); m_modFormat.formatName = U_("MnemoTroN SoundTracker"); m_modFormat.type = U_("st26"); m_modFormat.madeWithTracker = U_("SoundTracker 2.6"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; } else if(IsMagic(magic, "IT10")) { + InitializeGlobals(MOD_TYPE_MOD); m_modFormat.formatName = U_("Ice Tracker"); m_modFormat.type = U_("ice"); m_modFormat.madeWithTracker = U_("Ice Tracker 1.0 / 1.1"); @@ -2066,55 +2054,48 @@ MODSampleHeader sampleHeader; file.ReadStruct(sampleHeader); invalidBytes += ReadSample(sampleHeader, Samples[smp], m_szNames[smp], true); - } - if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) - { - return false; + if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) + return false; } const auto [numOrders, numTracks] = file.ReadArray<uint8, 2>(); if(numOrders > 128) - { return false; - } - uint8 tracks[128 * 4]; + std::array<uint8, 128 * 4> tracks; file.ReadArray(tracks); for(auto track : tracks) { if(track > numTracks) - { return false; - } } if(loadFlags == onlyVerifyHeader) - { return true; - } // Now we can be pretty sure that this is a valid MOD file. Set up default song settings. m_nChannels = 4; - m_nInstruments = 0; + SetupMODPanning(true); Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; m_nSamplePreAmp = 64; m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED); - - // Setup channel pan positions and volume - SetupMODPanning(); + m_playBehaviour.reset(kMODOneShotLoops); + m_playBehaviour.set(kMODIgnorePanning); + m_playBehaviour.set(kMODSampleSwap); // untested // Reading patterns Order().resize(numOrders); uint8 speed[2] = {0, 0}, speedPos = 0; - Patterns.ResizeArray(numOrders); + if(loadFlags & loadPatternData) + Patterns.ResizeArray(numOrders); for(PATTERNINDEX pat = 0; pat < numOrders; pat++) { Order()[pat] = pat; - if(!Patterns.Insert(pat, 64)) - continue; + if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) + break; for(CHANNELINDEX chn = 0; chn < 4; chn++) { |
From: <sv...@op...> - 2024-04-17 18:27:00
|
Author: sagamusix Date: Wed Apr 17 20:26:48 2024 New Revision: 20616 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20616 Log: [Imp] Puma: Avoid loading patterns if requested to do so. Modified: trunk/OpenMPT/soundlib/Load_puma.cpp Modified: trunk/OpenMPT/soundlib/Load_puma.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_puma.cpp Wed Apr 17 20:24:29 2024 (r20615) +++ trunk/OpenMPT/soundlib/Load_puma.cpp Wed Apr 17 20:26:48 2024 (r20616) @@ -218,20 +218,21 @@ return false; Order().resize(numOrders); + if(loadFlags & loadPatternData) + Patterns.ResizeArray(numOrders); for(ORDERINDEX ord = 0; ord < numOrders; ord++) { - const PATTERNINDEX pat = Patterns.InsertAny(numRows); - if(pat == PATTERNINDEX_INVALID) - return false; if(!orderData[ord].IsValid()) return false; - Order()[ord] = pat; + if(!(loadFlags & loadPatternData) || !Patterns.Insert(ord, numRows)) + continue; + Order()[ord] = ord; for(CHANNELINDEX chn = 0; chn < 4; chn++) { const auto &chnInfo = orderData[ord].channels[chn]; if(chnInfo.pattern >= patternData.size()) continue; - ModCommand *m = Patterns[pat].GetpModCommand(0, chn); + ModCommand *m = Patterns[ord].GetpModCommand(0, chn); // Auto-portmentos appear to stop on pattern transitions and revert to the note's original pitch. VolumeCommand autoPorta = VOLCMD_NONE; for(const auto &p : patternData[chnInfo.pattern]) @@ -270,7 +271,7 @@ } } if(orderData[ord].speed) - Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, orderData[ord].speed).RetryNextRow()); + Patterns[ord].WriteEffect(EffectWriter(CMD_SPEED, orderData[ord].speed).RetryNextRow()); } for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) |
From: <sv...@op...> - 2024-04-17 18:24:42
|
Author: sagamusix Date: Wed Apr 17 20:24:29 2024 New Revision: 20615 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20615 Log: [Ref] CPatternContainer::ClearPatterns was functionally equivalent to CPatternContainer::DestroyPatterns. Remove it. Modified: trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/patternContainer.cpp trunk/OpenMPT/soundlib/patternContainer.h Modified: trunk/OpenMPT/soundlib/Sndfile.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp Wed Apr 17 20:16:32 2024 (r20614) +++ trunk/OpenMPT/soundlib/Sndfile.cpp Wed Apr 17 20:24:29 2024 (r20615) @@ -214,7 +214,7 @@ SetMixLevels(MixLevels::Compatible); - Patterns.ClearPatterns(); + Patterns.DestroyPatterns(); Order.Initialize(); m_songName.clear(); Modified: trunk/OpenMPT/soundlib/patternContainer.cpp ============================================================================== --- trunk/OpenMPT/soundlib/patternContainer.cpp Wed Apr 17 20:16:32 2024 (r20614) +++ trunk/OpenMPT/soundlib/patternContainer.cpp Wed Apr 17 20:24:29 2024 (r20615) @@ -37,13 +37,6 @@ } -void CPatternContainer::ClearPatterns() -{ - DestroyPatterns(); - m_Patterns.assign(m_Patterns.size(), CPattern(*this)); -} - - void CPatternContainer::DestroyPatterns() { m_Patterns.clear(); Modified: trunk/OpenMPT/soundlib/patternContainer.h ============================================================================== --- trunk/OpenMPT/soundlib/patternContainer.h Wed Apr 17 20:16:32 2024 (r20614) +++ trunk/OpenMPT/soundlib/patternContainer.h Wed Apr 17 20:24:29 2024 (r20615) @@ -33,8 +33,6 @@ CPatternContainer &operator=(const CPatternContainer &other); CPatternContainer &operator=(CPatternContainer &&other) noexcept; - // Empty and initialize all patterns. - void ClearPatterns(); // Delete all patterns. void DestroyPatterns(); |
From: <sv...@op...> - 2024-04-17 18:16:44
|
Author: sagamusix Date: Wed Apr 17 20:16:32 2024 New Revision: 20614 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20614 Log: [Imp] MO3: It's possible to establish a clear upper bound on the size of pattern track data. Reject any track that is too big in size. Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp Wed Apr 17 19:00:21 2024 (r20613) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp Wed Apr 17 20:16:32 2024 (r20614) @@ -989,6 +989,10 @@ for(auto &track : tracks) { uint32 len = musicChunk.ReadUint32LE(); + // A pattern can be at most 65535 rows long, one row can contain at most 15 events (with the status bytes, that 31 bytes per row). + // Leaving some margin for error, that gives us an upper limit of 2MB per track. + if(len >= 0x20'0000) + return false; track = musicChunk.ReadChunk(len); } |
From: <sv...@op...> - 2024-04-17 17:00:28
|
Author: sagamusix Date: Wed Apr 17 19:00:21 2024 New Revision: 20613 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20613 Log: [Mod] MO3: Reject chunks that are bigger than the file. Optimize loader code to not keep two copies of string length. Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp Wed Apr 17 18:59:33 2024 (r20612) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp Wed Apr 17 19:00:21 2024 (r20613) @@ -180,7 +180,7 @@ uint8le midiPatch; uint8le midiBend; uint8le globalVol; // 0...128 - uint16le panning; // 0...256 if enabled, 0xFFFF otherwise + uint16le panning; // 0...256 if enabled, 0xFFFF otherwise uint8le nna; uint8le pps; uint8le ppc; @@ -488,8 +488,7 @@ strLen -= 3; if(strLen < 0) { - // means LZ ptr with same previous relative LZ ptr (saved one) - m_strOffset = m_previousPtr; // restore previous Ptr + // reuse same previous relative LZ ptr (m_strOffset is not re-computed) strLen++; } else { @@ -505,8 +504,9 @@ lengthAdjust++; // length is always at least 1 if(m_strOffset < -32000) lengthAdjust++; - m_previousPtr = m_strOffset; // save current Ptr } + if(m_strOffset >= 0 || -static_cast<ptrdiff_t>(streamCache.size()) > m_strOffset) + break; // read the next 2 bits as part of strLen READ_CTRL_BIT; @@ -523,8 +523,6 @@ if(strLen <= 0 || m_totalRemain < static_cast<uint32>(strLen)) break; - if(m_strOffset >= 0 || -static_cast<ptrdiff_t>(streamCache.size()) > m_strOffset) - break; // Copy previous string // Need to do this in two steps (allocate, then copy) as source and destination may overlap (e.g. strOffset = -1, strLen = 2 repeats last character twice) @@ -561,7 +559,6 @@ mutable uint16 m_data = 0; mutable int32 m_strLen = 0; // Length of repeated string mutable int32 m_strOffset = 0; // Offset of repeated string - mutable uint32 m_previousPtr = 0; mutable uint32 m_totalRemain = 0; }; @@ -794,7 +791,7 @@ struct MO3ContainerHeader { - char magic[3]; // MO3 + char magic[3]; // MO3 uint8le version; uint32le musicSize; }; @@ -1389,7 +1386,10 @@ PLUGINDEX plug = musicChunk.ReadUint8(); if(!plug) break; - FileReader pluginChunk = musicChunk.ReadChunk(musicChunk.ReadUint32LE()); + uint32 len = musicChunk.ReadUint32LE(); + if(len >= containerHeader.musicSize || containerHeader.musicSize - len < musicChunk.GetPosition()) + return false; + FileReader pluginChunk = musicChunk.ReadChunk(len); #ifndef NO_PLUGINS if(plug <= MAX_MIXPLUGINS) { @@ -1406,6 +1406,8 @@ { uint32 id = musicChunk.ReadUint32LE(); uint32 len = musicChunk.ReadUint32LE(); + if(len >= containerHeader.musicSize || containerHeader.musicSize - len < musicChunk.GetPosition()) + return false; FileReader chunk = musicChunk.ReadChunk(len); switch(id) { |
From: <sv...@op...> - 2024-04-17 16:59:51
|
Author: sagamusix Date: Wed Apr 17 18:59:33 2024 New Revision: 20612 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20612 Log: [Mod] MOD: Reserved script size was still off by one... Modified: trunk/OpenMPT/soundlib/Load_mod.cpp Modified: trunk/OpenMPT/soundlib/Load_mod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp Tue Apr 16 22:57:33 2024 (r20611) +++ trunk/OpenMPT/soundlib/Load_mod.cpp Wed Apr 17 18:59:33 2024 (r20612) @@ -1387,7 +1387,7 @@ } auto &events = instr->synth.m_scripts.emplace_back(); - events.reserve(std::min(loopEnd + 1, 65)); + events.reserve(std::min(loopEnd + 2, 65)); const auto waveforms = file.ReadArray<uint8, 64>(); const auto volumes = file.ReadArray<uint8, 64>(); for(uint8 i = 0; i < 64; i++) |
From: <sv...@op...> - 2024-04-16 21:37:23
|
Author: sagamusix Date: Tue Apr 16 22:21:35 2024 New Revision: 20610 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20610 Log: [Fix] MO3: It was impossible to duplicate sample data from a sample compressed with Ogg Vorbis. [Ref] MO3: Samples are now read after all other music data as a preparation for an upcoming change. Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp Tue Apr 16 15:27:34 2024 (r20609) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp Tue Apr 16 22:21:35 2024 (r20610) @@ -67,26 +67,26 @@ { enum MO3HeaderFlags { - linearSlides = 0x0001, - isS3M = 0x0002, - s3mFastSlides = 0x0004, - isMTM = 0x0008, // Actually this is simply "not XM". But if none of the S3M, MOD and IT flags are set, it's an MTM. - s3mAmigaLimits = 0x0010, + linearSlides = 0x0001, + isS3M = 0x0002, + s3mFastSlides = 0x0004, + isMTM = 0x0008, // Actually this is simply "not XM". But if none of the S3M, MOD and IT flags are set, it's an MTM. + s3mAmigaLimits = 0x0010, // 0x20 and 0x40 have been used in old versions for things that can be inferred from the file format anyway. // The official UNMO3 ignores them. - isMOD = 0x0080, - isIT = 0x0100, - instrumentMode = 0x0200, - itCompatGxx = 0x0400, - itOldFX = 0x0800, - modplugMode = 0x10000, - unknown = 0x20000, // Always set (internal BASS flag to designate modules) - modVBlank = 0x80000, - hasPlugins = 0x100000, - extFilterRange = 0x200000, + isMOD = 0x0080, + isIT = 0x0100, + instrumentMode = 0x0200, + itCompatGxx = 0x0400, + itOldFX = 0x0800, + modplugMode = 0x10000, + unknown = 0x20000, // Always set (internal BASS flag to designate modules) + modVBlank = 0x80000, + hasPlugins = 0x100000, + extFilterRange = 0x200000, }; - uint8le numChannels; // 1...64 (limited by channel panning and volume) + uint8le numChannels; // 1...64 (limited by channel panning and volume) uint16le numOrders; uint16le restartPos; uint16le numPatterns; @@ -95,12 +95,12 @@ uint16le numSamples; uint8le defaultSpeed; uint8le defaultTempo; - uint32le flags; // See MO3HeaderFlags - uint8le globalVol; // 0...128 in IT, 0...64 in S3M - uint8le panSeparation; // 0...128 in IT - int8le sampleVolume; // Only used in IT - uint8le chnVolume[64]; // 0...64 - uint8le chnPan[64]; // 0...256, 127 = surround + uint32le flags; // See MO3HeaderFlags + uint8le globalVol; // 0...128 in IT, 0...64 in S3M + uint8le panSeparation; // 0...128 in IT + int8le sampleVolume; // Only used in IT + uint8le chnVolume[64]; // 0...64 + uint8le chnPan[64]; // 0...256, 127 = surround uint8le sfxMacros[16]; uint8le fixedMacros[128][2]; }; @@ -112,14 +112,14 @@ { enum MO3EnvelopeFlags { - envEnabled = 0x01, - envSustain = 0x02, - envLoop = 0x04, - envFilter = 0x10, - envCarry = 0x20, + envEnabled = 0x01, + envSustain = 0x02, + envLoop = 0x04, + envFilter = 0x10, + envCarry = 0x20, }; - uint8le flags; // See MO3EnvelopeFlags + uint8le flags; // See MO3EnvelopeFlags uint8le numNodes; uint8le sustainStart; uint8le sustainEnd; @@ -157,11 +157,11 @@ { enum MO3InstrumentFlags { - playOnMIDI = 0x01, - mute = 0x02, + playOnMIDI = 0x01, + mute = 0x02, }; - uint32le flags; // See MO3InstrumentFlags + uint32le flags; // See MO3InstrumentFlags uint16le sampleMap[120][2]; MO3Envelope volEnv; MO3Envelope panEnv; @@ -172,23 +172,23 @@ uint8le sweep; uint8le depth; uint8le rate; - } vibrato; // Applies to all samples of this instrument (XM) + } vibrato; // Applies to all samples of this instrument (XM) uint16le fadeOut; uint8le midiChannel; uint8le midiBank; uint8le midiPatch; uint8le midiBend; - uint8le globalVol; // 0...128 - uint16le panning; // 0...256 if enabled, 0xFFFF otherwise + uint8le globalVol; // 0...128 + uint16le panning; // 0...256 if enabled, 0xFFFF otherwise uint8le nna; uint8le pps; uint8le ppc; uint8le dct; uint8le dca; - uint16le volSwing; // 0...100 - uint16le panSwing; // 0...256 - uint8le cutoff; // 0...127, + 128 if enabled - uint8le resonance; // 0...127, + 128 if enabled + uint16le volSwing; // 0...100 + uint16le panSwing; // 0...256 + uint8le cutoff; // 0...127, + 128 if enabled + uint8le resonance; // 0...127, + 128 if enabled // Convert MO3 instrument data into OpenMPT's internal instrument format void ConvertToMPT(ModInstrument &mptIns, MODTYPE type) const @@ -281,23 +281,23 @@ smpCompressionMask = 0x1000 | 0x2000 | 0x4000 | 0x8000 }; - uint32le freqFinetune; // Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM + uint32le freqFinetune; // Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM int8le transpose; - uint8le defaultVolume; // 0...64 - uint16le panning; // 0...256 if enabled, 0xFFFF otherwise + uint8le defaultVolume; // 0...64 + uint16le panning; // 0...256 if enabled, 0xFFFF otherwise uint32le length; uint32le loopStart; uint32le loopEnd; - uint16le flags; // See MO3SampleFlags + uint16le flags; // See MO3SampleFlags uint8le vibType; uint8le vibSweep; uint8le vibDepth; uint8le vibRate; - uint8le globalVol; // 0...64 in IT, in XM it represents the instrument number + uint8le globalVol; // 0...64 in IT, in XM it represents the instrument number uint32le sustainStart; uint32le sustainEnd; int32le compressedSize; - uint16le encoderDelay; // MP3: Ignore first n bytes of decoded output. Ogg: Shared Ogg header size + uint16le encoderDelay; // MP3: Ignore first n bytes of decoded output. Ogg: Shared Ogg header size // Convert MO3 sample data into OpenMPT's internal instrument format void ConvertToMPT(ModSample &mptSmp, MODTYPE type, bool frequencyIsHertz) const @@ -353,13 +353,13 @@ // We need all this information for Ogg-compressed samples with shared headers: // A shared header can be taken from a sample that has not been read yet, so // we first need to read all headers, and then load the Ogg samples afterwards. -struct MO3SampleChunk +struct MO3SampleInfo { FileReader chunk; - uint16 headerSize; - int16 sharedHeader; - MO3SampleChunk(const FileReader &chunk_ = FileReader(), uint16 headerSize_ = 0, int16 sharedHeader_ = 0) - : chunk(chunk_), headerSize(headerSize_), sharedHeader(sharedHeader_) {} + const MO3Sample smpHeader; + const int16 sharedHeader; + MO3SampleInfo(MO3Sample smpHeader, int16 sharedHeader) + : smpHeader{smpHeader}, sharedHeader{sharedHeader} {} }; @@ -1271,10 +1271,9 @@ if(isSampleMode) m_nInstruments = 0; - std::vector<MO3SampleChunk> sampleChunks(m_nSamples); + std::vector<MO3SampleInfo> sampleInfos; const bool frequencyIsHertz = (version >= 5 || !(fileHeader.flags & MO3FileHeader::linearSlides)); - bool unsupportedSamples = false; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { ModSample &sample = Samples[smp]; @@ -1298,130 +1297,314 @@ sharedOggHeader = musicChunk.ReadInt16LE(); } - if(!(loadFlags & loadSampleData)) - continue; + if(loadFlags & loadSampleData) + { + sampleInfos.reserve(m_nSamples); + sampleInfos.emplace_back(smpHeader, sharedOggHeader); + } + } - const uint32 compression = (smpHeader.flags & MO3Sample::smpCompressionMask); - if(!compression && smpHeader.compressedSize == 0) + if(m_nType == MOD_TYPE_XM) + { + // Transfer XM instrument vibrato to samples + for(INSTRUMENTINDEX ins = 0; ins < m_nInstruments; ins++) { - // Uncompressed sample - SampleIO( - (smpHeader.flags & MO3Sample::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, - (smpHeader.flags & MO3Sample::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono, - SampleIO::littleEndian, - SampleIO::signedPCM) - .ReadSample(Samples[smp], file); - } else if(smpHeader.compressedSize < 0 && (smp + smpHeader.compressedSize) > 0) + PropagateXMAutoVibrato(ins + 1, static_cast<VibratoType>(instrVibrato[ins].type.get()), instrVibrato[ins].sweep, instrVibrato[ins].depth, instrVibrato[ins].rate); + } + } + + if((fileHeader.flags & MO3FileHeader::hasPlugins) && musicChunk.CanRead(1)) + { + // Plugin data + uint8 pluginFlags = musicChunk.ReadUint8(); + if(pluginFlags & 1) { - // Duplicate sample - sample.CopyWaveform(Samples[smp + smpHeader.compressedSize]); - } else if(smpHeader.compressedSize > 0) + // Channel plugins + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + { + ChnSettings[chn].nMixPlugin = static_cast<PLUGINDEX>(musicChunk.ReadUint32LE()); + } + } + while(musicChunk.CanRead(1)) { - if(smpHeader.flags & MO3Sample::smp16Bit) - sample.uFlags.set(CHN_16BIT); - if(smpHeader.flags & MO3Sample::smpStereo) - sample.uFlags.set(CHN_STEREO); - - FileReader sampleData = file.ReadChunk(smpHeader.compressedSize); - const uint8 numChannels = sample.GetNumChannels(); - - if(compression == MO3Sample::smpDeltaCompression || compression == MO3Sample::smpDeltaPrediction) - { - // In the best case, MO3 compression represents each sample point as two bits. - // As a result, if we have a file length of n, we know that the sample can be at most n*4 sample points long. - auto maxLength = sampleData.GetLength(); - uint8 maxSamplesPerByte = 4 / numChannels; - if(Util::MaxValueOfType(maxLength) / maxSamplesPerByte >= maxLength) - maxLength *= maxSamplesPerByte; - else - maxLength = Util::MaxValueOfType(maxLength); - LimitMax(sample.nLength, mpt::saturate_cast<SmpLength>(maxLength)); + PLUGINDEX plug = musicChunk.ReadUint8(); + if(!plug) + break; + FileReader pluginChunk = musicChunk.ReadChunk(musicChunk.ReadUint32LE()); +#ifndef NO_PLUGINS + if(plug <= MAX_MIXPLUGINS) + { + ReadMixPluginChunk(pluginChunk, m_MixPlugins[plug - 1]); } +#endif // NO_PLUGINS + } + } - if(compression == MO3Sample::smpDeltaCompression) + mpt::ustring madeWithTracker; + uint16 cwtv = 0; + uint16 cmwt = 0; + while(musicChunk.CanRead(8)) + { + uint32 id = musicChunk.ReadUint32LE(); + uint32 len = musicChunk.ReadUint32LE(); + FileReader chunk = musicChunk.ReadChunk(len); + switch(id) + { + case MagicLE("VERS"): + // Tracker magic bytes (depending on format) + switch(m_nType) { - if(sample.AllocateSample()) + case MOD_TYPE_IT: + cwtv = chunk.ReadUint16LE(); + cmwt = chunk.ReadUint16LE(); + /*switch(cwtv >> 12) { - if(smpHeader.flags & MO3Sample::smp16Bit) - UnpackMO3DeltaSample<MO3Delta16BitParams>(sampleData, sample.sample16(), sample.nLength, numChannels); - else - UnpackMO3DeltaSample<MO3Delta8BitParams>(sampleData, sample.sample8(), sample.nLength, numChannels); - } - } else if(compression == MO3Sample::smpDeltaPrediction) + + }*/ + break; + case MOD_TYPE_S3M: + cwtv = chunk.ReadUint16LE(); + break; + case MOD_TYPE_XM: + chunk.ReadString<mpt::String::spacePadded>(madeWithTracker, mpt::Charset::CP437, std::min(FileReader::pos_type(32), chunk.GetLength())); + break; + case MOD_TYPE_MTM: { - if(sample.AllocateSample()) - { - if(smpHeader.flags & MO3Sample::smp16Bit) - UnpackMO3DeltaPredictionSample<MO3Delta16BitParams>(sampleData, sample.sample16(), sample.nLength, numChannels); - else - UnpackMO3DeltaPredictionSample<MO3Delta8BitParams>(sampleData, sample.sample8(), sample.nLength, numChannels); - } - } else if(compression == MO3Sample::smpCompressionOgg || compression == MO3Sample::smpSharedOgg) + uint8 mtmVersion = chunk.ReadUint8(); + madeWithTracker = MPT_UFORMAT("MultiTracker {}.{}")(mtmVersion >> 4, mtmVersion & 0x0F); + } + break; + default: + break; + } + break; + case MagicLE("PRHI"): + m_nDefaultRowsPerBeat = chunk.ReadUint8(); + m_nDefaultRowsPerMeasure = chunk.ReadUint8(); + break; + case MagicLE("MIDI"): + // Full MIDI config + chunk.ReadStruct<MIDIMacroConfigData>(m_MidiCfg); + m_MidiCfg.Sanitize(); + break; + case MagicLE("OMPT"): + // Read pattern names: "PNAM" + if(chunk.ReadMagic("PNAM")) { - // Since shared Ogg headers can stem from a sample that has not been read yet, postpone Ogg import. - sampleChunks[smp - 1] = MO3SampleChunk(sampleData, smpHeader.encoderDelay, sharedOggHeader); - } else if(compression == MO3Sample::smpCompressionMPEG) - { - // Old MO3 encoders didn't remove LAME info frames. This is unfortunate since the encoder delay - // specified in the sample header does not take the gapless information from the LAME info frame - // into account. We should not depend on the MP3 decoder's capabilities to read or ignore such frames: - // - libmpg123 has MPG123_IGNORE_INFOFRAME but that requires API version 31 (mpg123 v1.14) or higher - // - Media Foundation does (currently) not read LAME gapless information at all - // So we just play safe and remove such frames. - FileReader mpegData(sampleData); - MPEGFrame frame(sampleData); - uint16 frameDelay = frame.numSamples * 2; - if(frame.isLAME && smpHeader.encoderDelay >= frameDelay) + FileReader patterns = chunk.ReadChunk(chunk.ReadUint32LE()); + const PATTERNINDEX namedPats = std::min(static_cast<PATTERNINDEX>(patterns.GetLength() / MAX_PATTERNNAME), Patterns.Size()); + + for(PATTERNINDEX pat = 0; pat < namedPats; pat++) { - // The info frame does not produce any output, but still counts towards the encoder delay. - smpHeader.encoderDelay -= frameDelay; - sampleData.Seek(frame.frameSize); - mpegData = sampleData.ReadChunk(sampleData.BytesLeft()); + char patName[MAX_PATTERNNAME]; + patterns.ReadString<mpt::String::maybeNullTerminated>(patName, MAX_PATTERNNAME); + Patterns[pat].SetName(patName); } + } - if(ReadMP3Sample(smp, mpegData, true, true) || ReadMediaFoundationSample(smp, mpegData, true)) - { - if(smpHeader.encoderDelay > 0 && smpHeader.encoderDelay < sample.GetSampleSizeInBytes()) - { - SmpLength delay = smpHeader.encoderDelay / sample.GetBytesPerSample(); - memmove(sample.sampleb(), sample.sampleb() + smpHeader.encoderDelay, sample.GetSampleSizeInBytes() - smpHeader.encoderDelay); - sample.nLength -= delay; - } - LimitMax(sample.nLength, smpHeader.length); - } else + // Read channel names: "CNAM" + if(chunk.ReadMagic("CNAM")) + { + FileReader channels = chunk.ReadChunk(chunk.ReadUint32LE()); + const CHANNELINDEX namedChans = std::min(static_cast<CHANNELINDEX>(channels.GetLength() / MAX_CHANNELNAME), GetNumChannels()); + for(CHANNELINDEX chn = 0; chn < namedChans; chn++) { - unsupportedSamples = true; + channels.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[chn].szName, MAX_CHANNELNAME); } - } else if(compression == MO3Sample::smpOPLInstrument) + } + + LoadExtendedInstrumentProperties(chunk); + LoadExtendedSongProperties(chunk, true); + if(cwtv > 0x0889 && cwtv <= 0x8FF) + { + m_nType = MOD_TYPE_MPT; + LoadMPTMProperties(chunk, cwtv); + } + + if(m_dwLastSavedWithVersion) + { + madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); + } + break; + } + } + + if((GetType() == MOD_TYPE_IT && cwtv >= 0x0100 && cwtv < 0x0214) + || (GetType() == MOD_TYPE_S3M && cwtv >= 0x3100 && cwtv < 0x3214) + || (GetType() == MOD_TYPE_S3M && cwtv >= 0x1300 && cwtv < 0x1320)) + { + // Ignore MIDI data in files made with IT older than version 2.14 and old ST3 versions. + m_MidiCfg.ClearZxxMacros(); + } + + if(fileHeader.flags & MO3FileHeader::modplugMode) + { + // Apply some old ModPlug (mis-)behaviour + if(!m_dwLastSavedWithVersion) + { + // These fixes are only applied when the OpenMPT version number is not known, as otherwise the song upgrade feature will take care of it. + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { - OPLPatch patch; - if(sampleData.ReadArray(patch)) + if(ModInstrument *ins = Instruments[i]) { - sample.SetAdlib(true, patch); + // Fix pitch / filter envelope being shortened by one tick (for files before v1.20) + ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType()); + // Fix excessive pan swing range (for files before v1.26) + ins->nPanSwing = static_cast<uint8>((ins->nPanSwing + 3) / 4u); } - } else - { - unsupportedSamples = true; } } + if(m_dwLastSavedWithVersion < MPT_V("1.18.00.00")) + { + m_playBehaviour.reset(kITOffset); + m_playBehaviour.reset(kFT2ST3OffsetOutOfRange); + } + if(m_dwLastSavedWithVersion < MPT_V("1.23.00.00")) + m_playBehaviour.reset(kFT2Periods); + if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) + m_playBehaviour.reset(kITInstrWithNoteOff); } - // Now we can load Ogg samples with shared headers. - if(loadFlags & loadSampleData) + if(madeWithTracker.empty()) + madeWithTracker = MPT_UFORMAT("MO3 v{}")(version); + else + madeWithTracker = MPT_UFORMAT("MO3 v{} ({})")(version, madeWithTracker); + + m_modFormat.formatName = MPT_UFORMAT("Un4seen MO3 v{}")(version); + m_modFormat.type = U_("mo3"); + + switch(GetType()) { - for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + case MOD_TYPE_MTM: + m_modFormat.originalType = U_("mtm"); + m_modFormat.originalFormatName = U_("MultiTracker"); + break; + case MOD_TYPE_MOD: + m_modFormat.originalType = U_("mod"); + m_modFormat.originalFormatName = U_("Generic MOD"); + break; + case MOD_TYPE_XM: + m_modFormat.originalType = U_("xm"); + m_modFormat.originalFormatName = U_("FastTracker 2"); + break; + case MOD_TYPE_S3M: + m_modFormat.originalType = U_("s3m"); + m_modFormat.originalFormatName = U_("Scream Tracker 3"); + break; + case MOD_TYPE_IT: + m_modFormat.originalType = U_("it"); + if(cmwt) + m_modFormat.originalFormatName = MPT_UFORMAT("Impulse Tracker {}.{}")(cmwt >> 8, mpt::ufmt::hex0<2>(cmwt & 0xFF)); + else + m_modFormat.originalFormatName = U_("Impulse Tracker"); + break; + case MOD_TYPE_MPT: + m_modFormat.originalType = U_("mptm"); + m_modFormat.originalFormatName = U_("OpenMPT MPTM"); + break; + default: + MPT_ASSERT_NOTREACHED(); + } + m_modFormat.madeWithTracker = std::move(madeWithTracker); + if(m_dwLastSavedWithVersion) + m_modFormat.charset = mpt::Charset::Windows1252; + else if(GetType() == MOD_TYPE_MOD) + m_modFormat.charset = mpt::Charset::Amiga_no_C1; + else + m_modFormat.charset = mpt::Charset::CP437; + + if(!(loadFlags & loadSampleData)) + return true; + + bool unsupportedSamples = false; + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + { + MO3SampleInfo &smpInfo = sampleInfos[smp - 1]; + const MO3Sample &smpHeader = smpInfo.smpHeader; + const uint32 compression = (smpHeader.flags & MO3Sample::smpCompressionMask); + + if(!compression && smpHeader.compressedSize == 0) { - MO3SampleChunk &sampleChunk = sampleChunks[smp - 1]; - // Is this an Ogg sample? - if(!sampleChunk.chunk.IsValid()) - continue; + // Uncompressed sample + SampleIO( + (smpHeader.flags & MO3Sample::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, + (smpHeader.flags & MO3Sample::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(Samples[smp], file); + } else if(smpHeader.compressedSize > 0) + { + // Compressed sample; we read those in a second pass because Ogg samples with shared headers may reference a later sample's header + smpInfo.chunk = file.ReadChunk(smpHeader.compressedSize); + } + } + + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + { + ModSample &sample = Samples[smp]; + MO3SampleInfo &smpInfo = sampleInfos[smp - 1]; + const MO3Sample &smpHeader = smpInfo.smpHeader; - SAMPLEINDEX sharedOggHeader = (smp + sampleChunk.sharedHeader > 0) ? static_cast<SAMPLEINDEX>(smp + sampleChunk.sharedHeader) : smp; + if(smpHeader.compressedSize < 0 && (smp + smpHeader.compressedSize) > 0) + { + // Duplicate sample + sample.CopyWaveform(Samples[smp + smpHeader.compressedSize]); + continue; + } + + // Not a compressed sample? + if(!smpInfo.chunk.IsValid()) + continue; + + if(smpHeader.flags & MO3Sample::smp16Bit) + sample.uFlags.set(CHN_16BIT); + if(smpHeader.flags & MO3Sample::smpStereo) + sample.uFlags.set(CHN_STEREO); + + FileReader &sampleData = smpInfo.chunk; + const uint8 numChannels = sample.GetNumChannels(); + const uint32 compression = (smpHeader.flags & MO3Sample::smpCompressionMask); + + if(compression == MO3Sample::smpDeltaCompression || compression == MO3Sample::smpDeltaPrediction) + { + // In the best case, MO3 compression represents each sample point as two bits. + // As a result, if we have a file length of n, we know that the sample can be at most n*4 sample points long. + auto maxLength = sampleData.GetLength(); + uint8 maxSamplesPerByte = 4 / numChannels; + if(Util::MaxValueOfType(maxLength) / maxSamplesPerByte >= maxLength) + maxLength *= maxSamplesPerByte; + else + maxLength = Util::MaxValueOfType(maxLength); + LimitMax(sample.nLength, mpt::saturate_cast<SmpLength>(maxLength)); + } + + if(compression == MO3Sample::smpDeltaCompression) + { + if(sample.AllocateSample()) + { + if(smpHeader.flags & MO3Sample::smp16Bit) + UnpackMO3DeltaSample<MO3Delta16BitParams>(sampleData, sample.sample16(), sample.nLength, numChannels); + else + UnpackMO3DeltaSample<MO3Delta8BitParams>(sampleData, sample.sample8(), sample.nLength, numChannels); + } + } else if(compression == MO3Sample::smpDeltaPrediction) + { + if(sample.AllocateSample()) + { + if(smpHeader.flags & MO3Sample::smp16Bit) + UnpackMO3DeltaPredictionSample<MO3Delta16BitParams>(sampleData, sample.sample16(), sample.nLength, numChannels); + else + UnpackMO3DeltaPredictionSample<MO3Delta8BitParams>(sampleData, sample.sample8(), sample.nLength, numChannels); + } + } else if(compression == MO3Sample::smpCompressionOgg || compression == MO3Sample::smpSharedOgg) + { + const uint16 sharedHeaderSize = smpHeader.encoderDelay; + SAMPLEINDEX sharedOggHeader = (smp + smpInfo.sharedHeader > 0) ? static_cast<SAMPLEINDEX>(smp + smpInfo.sharedHeader) : smp; // Which chunk are we going to read the header from? // Note: Every Ogg stream has a unique serial number. // stb_vorbis (currently) ignores this serial number so we can just stitch // together our sample without adjusting the shared header's serial number. - const bool sharedHeader = sharedOggHeader != smp && sharedOggHeader > 0 && sharedOggHeader <= m_nSamples && sampleChunk.headerSize > 0; + const bool sharedHeader = sharedOggHeader != smp && sharedOggHeader > 0 && sharedOggHeader <= m_nSamples && sharedHeaderSize > 0; #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) @@ -1448,8 +1631,8 @@ std::ostringstream mergedStream(std::ios::binary); mergedStream.imbue(std::locale::classic()); - sampleChunks[sharedOggHeader - 1].chunk.Rewind(); - FileReader sharedChunk = sampleChunks[sharedOggHeader - 1].chunk.ReadChunk(sampleChunk.headerSize); + sampleInfos[sharedOggHeader - 1].chunk.Rewind(); + FileReader sharedChunk = sampleInfos[sharedOggHeader - 1].chunk.ReadChunk(sharedHeaderSize); sharedChunk.Rewind(); std::vector<uint32> streamSerials; @@ -1472,7 +1655,7 @@ } streamSerials.clear(); - while(Ogg::ReadPageAndSkipJunk(sampleChunk.chunk, oggPageInfo, oggPageData)) + while(Ogg::ReadPageAndSkipJunk(smpInfo.chunk, oggPageInfo, oggPageData)) { auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number); if(it == streamSerials.end()) @@ -1497,8 +1680,8 @@ std::ostringstream mergedStream(std::ios::binary); mergedStream.imbue(std::locale::classic()); - sampleChunks[sharedOggHeader - 1].chunk.Rewind(); - FileReader sharedChunk = sampleChunks[sharedOggHeader - 1].chunk.ReadChunk(sampleChunk.headerSize); + sampleInfos[sharedOggHeader - 1].chunk.Rewind(); + FileReader sharedChunk = sampleInfos[sharedOggHeader - 1].chunk.ReadChunk(sharedHeaderSize); sharedChunk.Rewind(); std::vector<uint32> dataStreamSerials; @@ -1508,7 +1691,7 @@ // Gather bitstream serial numbers form sample data chunk dataStreamSerials.clear(); - while(Ogg::ReadPageAndSkipJunk(sampleChunk.chunk, oggPageInfo, oggPageData)) + while(Ogg::ReadPageAndSkipJunk(smpInfo.chunk, oggPageInfo, oggPageData)) { if(!mpt::contains(dataStreamSerials, oggPageInfo.header.bitstream_serial_number)) { @@ -1566,8 +1749,8 @@ std::string mergedStreamData = mergedStream.str(); mergedData.insert(mergedData.end(), mergedStreamData.begin(), mergedStreamData.end()); - sampleChunk.chunk.Rewind(); - FileReader::PinnedView sampleChunkView = sampleChunk.chunk.GetPinnedView(); + smpInfo.chunk.Rewind(); + FileReader::PinnedView sampleChunkView = smpInfo.chunk.GetPinnedView(); mpt::span<const char> sampleChunkViewSpan = mpt::byte_cast<mpt::span<const char>>(sampleChunkView.span()); mergedData.insert(mergedData.end(), sampleChunkViewSpan.begin(), sampleChunkViewSpan.end()); @@ -1575,21 +1758,20 @@ } FileReader mergedDataChunk(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(mergedData))); - FileReader &sampleData = sharedHeader ? mergedDataChunk : sampleChunk.chunk; - FileReader &headerChunk = sampleData; + FileReader &sampleChunk = sharedHeader ? mergedDataChunk : smpInfo.chunk; + FileReader &headerChunk = sampleChunk; #else // !(MPT_WITH_VORBIS && MPT_WITH_VORBISFILE) - FileReader &sampleData = sampleChunk.chunk; - FileReader &headerChunk = sharedHeader ? sampleChunks[sharedOggHeader - 1].chunk : sampleData; + FileReader &headerChunk = sharedHeader ? sampleInfos[sharedOggHeader - 1].chunk : sampleData; #if defined(MPT_WITH_STBVORBIS) - std::size_t initialRead = sharedHeader ? sampleChunk.headerSize : headerChunk.GetLength(); + std::size_t initialRead = sharedHeader ? sharedHeaderSize : headerChunk.GetLength(); #endif // MPT_WITH_STBVORBIS #endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE headerChunk.Rewind(); - if(sharedHeader && !headerChunk.CanRead(sampleChunk.headerSize)) + if(sharedHeader && !headerChunk.CanRead(sharedHeaderSize)) continue; #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) @@ -1601,14 +1783,13 @@ &VorbisfileFilereaderTell}; OggVorbis_File vf; MemsetZero(vf); - if(ov_open_callbacks(mpt::void_ptr<FileReader>(&sampleData), &vf, nullptr, 0, callbacks) == 0) + if(ov_open_callbacks(mpt::void_ptr<FileReader>(&sampleChunk), &vf, nullptr, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples vorbis_info *vi = ov_info(&vf, -1); if(vi && vi->rate > 0 && vi->channels > 0) { - ModSample &sample = Samples[smp]; sample.AllocateSample(); SmpLength offset = 0; int channels = vi->channels; @@ -1688,7 +1869,6 @@ if(vorb) { // Header has been read, proceed to reading the sample data - ModSample &sample = Samples[smp]; sample.AllocateSample(); SmpLength offset = 0; while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0)) @@ -1725,218 +1905,52 @@ unsupportedSamples = true; #endif // VORBIS - } - } - - if(m_nType == MOD_TYPE_XM) - { - // Transfer XM instrument vibrato to samples - for(INSTRUMENTINDEX ins = 0; ins < m_nInstruments; ins++) + } else if(compression == MO3Sample::smpCompressionMPEG) { - PropagateXMAutoVibrato(ins + 1, static_cast<VibratoType>(instrVibrato[ins].type.get()), instrVibrato[ins].sweep, instrVibrato[ins].depth, instrVibrato[ins].rate); - } - } - - if((fileHeader.flags & MO3FileHeader::hasPlugins) && musicChunk.CanRead(1)) - { - // Plugin data - uint8 pluginFlags = musicChunk.ReadUint8(); - if(pluginFlags & 1) - { - // Channel plugins - for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) - { - ChnSettings[chn].nMixPlugin = static_cast<PLUGINDEX>(musicChunk.ReadUint32LE()); - } - } - while(musicChunk.CanRead(1)) - { - PLUGINDEX plug = musicChunk.ReadUint8(); - if(!plug) - break; - FileReader pluginChunk = musicChunk.ReadChunk(musicChunk.ReadUint32LE()); -#ifndef NO_PLUGINS - if(plug <= MAX_MIXPLUGINS) - { - ReadMixPluginChunk(pluginChunk, m_MixPlugins[plug - 1]); - } -#endif // NO_PLUGINS - } - } - - mpt::ustring madeWithTracker; - uint16 cwtv = 0; - uint16 cmwt = 0; - while(musicChunk.CanRead(8)) - { - uint32 id = musicChunk.ReadUint32LE(); - uint32 len = musicChunk.ReadUint32LE(); - FileReader chunk = musicChunk.ReadChunk(len); - switch(id) - { - case MagicLE("VERS"): - // Tracker magic bytes (depending on format) - switch(m_nType) - { - case MOD_TYPE_IT: - cwtv = chunk.ReadUint16LE(); - cmwt = chunk.ReadUint16LE(); - /*switch(cwtv >> 12) - { - - }*/ - break; - case MOD_TYPE_S3M: - cwtv = chunk.ReadUint16LE(); - break; - case MOD_TYPE_XM: - chunk.ReadString<mpt::String::spacePadded>(madeWithTracker, mpt::Charset::CP437, std::min(FileReader::pos_type(32), chunk.GetLength())); - break; - case MOD_TYPE_MTM: - { - uint8 mtmVersion = chunk.ReadUint8(); - madeWithTracker = MPT_UFORMAT("MultiTracker {}.{}")(mtmVersion >> 4, mtmVersion & 0x0F); - } - break; - default: - break; - } - break; - case MagicLE("PRHI"): - m_nDefaultRowsPerBeat = chunk.ReadUint8(); - m_nDefaultRowsPerMeasure = chunk.ReadUint8(); - break; - case MagicLE("MIDI"): - // Full MIDI config - chunk.ReadStruct<MIDIMacroConfigData>(m_MidiCfg); - m_MidiCfg.Sanitize(); - break; - case MagicLE("OMPT"): - // Read pattern names: "PNAM" - if(chunk.ReadMagic("PNAM")) - { - FileReader patterns = chunk.ReadChunk(chunk.ReadUint32LE()); - const PATTERNINDEX namedPats = std::min(static_cast<PATTERNINDEX>(patterns.GetLength() / MAX_PATTERNNAME), Patterns.Size()); - - for(PATTERNINDEX pat = 0; pat < namedPats; pat++) - { - char patName[MAX_PATTERNNAME]; - patterns.ReadString<mpt::String::maybeNullTerminated>(patName, MAX_PATTERNNAME); - Patterns[pat].SetName(patName); + // Old MO3 encoders didn't remove LAME info frames. This is unfortunate since the encoder delay + // specified in the sample header does not take the gapless information from the LAME info frame + // into account. We should not depend on the MP3 decoder's capabilities to read or ignore such frames: + // - libmpg123 has MPG123_IGNORE_INFOFRAME but that requires API version 31 (mpg123 v1.14) or higher + // - Media Foundation does (currently) not read LAME gapless information at all + // So we just play safe and remove such frames. + FileReader mpegData(sampleData); + MPEGFrame frame(sampleData); + uint16 encoderDelay = smpHeader.encoderDelay; + uint16 frameDelay = frame.numSamples * 2; + if(frame.isLAME && encoderDelay >= frameDelay) + { + // The info frame does not produce any output, but still counts towards the encoder delay. + encoderDelay -= frameDelay; + sampleData.Seek(frame.frameSize); + mpegData = sampleData.ReadChunk(sampleData.BytesLeft()); + } + + if(ReadMP3Sample(smp, mpegData, true, true) || ReadMediaFoundationSample(smp, mpegData, true)) + { + if(encoderDelay > 0 && encoderDelay < sample.GetSampleSizeInBytes()) + { + SmpLength delay = encoderDelay / sample.GetBytesPerSample(); + memmove(sample.sampleb(), sample.sampleb() + encoderDelay, sample.GetSampleSizeInBytes() - encoderDelay); + sample.nLength -= delay; } - } - - // Read channel names: "CNAM" - if(chunk.ReadMagic("CNAM")) - { - FileReader channels = chunk.ReadChunk(chunk.ReadUint32LE()); - const CHANNELINDEX namedChans = std::min(static_cast<CHANNELINDEX>(channels.GetLength() / MAX_CHANNELNAME), GetNumChannels()); - for(CHANNELINDEX chn = 0; chn < namedChans; chn++) - { - channels.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[chn].szName, MAX_CHANNELNAME); - } - } - - LoadExtendedInstrumentProperties(chunk); - LoadExtendedSongProperties(chunk, true); - if(cwtv > 0x0889 && cwtv <= 0x8FF) - { - m_nType = MOD_TYPE_MPT; - LoadMPTMProperties(chunk, cwtv); - } - - if(m_dwLastSavedWithVersion) + LimitMax(sample.nLength, smpHeader.length); + } else { - madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); + unsupportedSamples = true; } - break; - } - } - - if((GetType() == MOD_TYPE_IT && cwtv >= 0x0100 && cwtv < 0x0214) - || (GetType() == MOD_TYPE_S3M && cwtv >= 0x3100 && cwtv < 0x3214) - || (GetType() == MOD_TYPE_S3M && cwtv >= 0x1300 && cwtv < 0x1320)) - { - // Ignore MIDI data in files made with IT older than version 2.14 and old ST3 versions. - m_MidiCfg.ClearZxxMacros(); - } - - if(fileHeader.flags & MO3FileHeader::modplugMode) - { - // Apply some old ModPlug (mis-)behaviour - if(!m_dwLastSavedWithVersion) + } else if(compression == MO3Sample::smpOPLInstrument) { - // These fixes are only applied when the OpenMPT version number is not known, as otherwise the song upgrade feature will take care of it. - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) + OPLPatch patch; + if(sampleData.ReadArray(patch)) { - if(ModInstrument *ins = Instruments[i]) - { - // Fix pitch / filter envelope being shortened by one tick (for files before v1.20) - ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType()); - // Fix excessive pan swing range (for files before v1.26) - ins->nPanSwing = static_cast<uint8>((ins->nPanSwing + 3) / 4u); - } + sample.SetAdlib(true, patch); } - } - if(m_dwLastSavedWithVersion < MPT_V("1.18.00.00")) + } else { - m_playBehaviour.reset(kITOffset); - m_playBehaviour.reset(kFT2ST3OffsetOutOfRange); + unsupportedSamples = true; } - if(m_dwLastSavedWithVersion < MPT_V("1.23.00.00")) - m_playBehaviour.reset(kFT2Periods); - if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) - m_playBehaviour.reset(kITInstrWithNoteOff); } - if(madeWithTracker.empty()) - madeWithTracker = MPT_UFORMAT("MO3 v{}")(version); - else - madeWithTracker = MPT_UFORMAT("MO3 v{} ({})")(version, madeWithTracker); - - m_modFormat.formatName = MPT_UFORMAT("Un4seen MO3 v{}")(version); - m_modFormat.type = U_("mo3"); - - switch(GetType()) - { - case MOD_TYPE_MTM: - m_modFormat.originalType = U_("mtm"); - m_modFormat.originalFormatName = U_("MultiTracker"); - break; - case MOD_TYPE_MOD: - m_modFormat.originalType = U_("mod"); - m_modFormat.originalFormatName = U_("Generic MOD"); - break; - case MOD_TYPE_XM: - m_modFormat.originalType = U_("xm"); - m_modFormat.originalFormatName = U_("FastTracker 2"); - break; - case MOD_TYPE_S3M: - m_modFormat.originalType = U_("s3m"); - m_modFormat.originalFormatName = U_("Scream Tracker 3"); - break; - case MOD_TYPE_IT: - m_modFormat.originalType = U_("it"); - if(cmwt) - m_modFormat.originalFormatName = MPT_UFORMAT("Impulse Tracker {}.{}")(cmwt >> 8, mpt::ufmt::hex0<2>(cmwt & 0xFF)); - else - m_modFormat.originalFormatName = U_("Impulse Tracker"); - break; - case MOD_TYPE_MPT: - m_modFormat.originalType = U_("mptm"); - m_modFormat.originalFormatName = U_("OpenMPT MPTM"); - break; - default: - MPT_ASSERT_NOTREACHED(); - } - m_modFormat.madeWithTracker = std::move(madeWithTracker); - if(m_dwLastSavedWithVersion) - m_modFormat.charset = mpt::Charset::Windows1252; - else if(GetType() == MOD_TYPE_MOD) - m_modFormat.charset = mpt::Charset::Amiga_no_C1; - else - m_modFormat.charset = mpt::Charset::CP437; - if(unsupportedSamples) { AddToLog(LogWarning, U_("Some compressed samples could not be loaded because they use an unsupported codec.")); |
From: <sv...@op...> - 2024-04-16 21:07:24
|
Author: sagamusix Date: Tue Apr 16 22:57:33 2024 New Revision: 20611 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20611 Log: [Imp] MO3: Compressed music data is now uncompressed on-the-fly. This allows to reduce memory usage of some corrupted files, as we will only unpack as much data as we need, even if the header claims that the unpacked data is gigantic. Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp Tue Apr 16 22:21:35 2024 (r20610) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp Tue Apr 16 22:57:33 2024 (r20611) @@ -19,6 +19,7 @@ #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" +#include "mpt/io_read/filedata_base_unseekable_buffer.hpp" #include "Tables.h" #include "../common/version.h" @@ -404,99 +405,165 @@ } -static bool UnpackMO3Data(FileReader &file, std::vector<uint8> &uncompressed, const uint32 size) +class MO3FileReaderBuffer final : public mpt::IO::FileDataUnseekableBuffer { - if(!size) - return false; +public: + MO3FileReaderBuffer(const FileReader &file, uint32 targetSize, uint32 suggestedReserveSize) + : file{file} + , m_suggestedReserveSize{suggestedReserveSize} + , m_targetSize{targetSize} + , m_totalRemain{targetSize} + { + } - uint16 data = 0; - int8 carry = 0; // x86 carry (used to propagate the most significant bit from one byte to another) - int32 strLen = 0; // length of previous string - int32 strOffset; // string offset - uint32 previousPtr = 0; - - // Read first uncompressed byte - uncompressed.push_back(file.ReadUint8()); - uint32 remain = size - 1; - - while(remain > 0) - { - READ_CTRL_BIT; - if(!carry) - { - // a 0 ctrl bit means 'copy', not compressed byte - if(uint8 b; file.Read(b)) - uncompressed.push_back(b); - else - break; + bool UnpackedSuccessfully() const + { + return !m_totalRemain && !m_broken; + } + + auto SourcePosition() const + { + return file.GetPosition(); + } + +protected: + bool InternalEof() const override + { + return !m_totalRemain || m_broken; + } + + void InternalReadContinue(std::vector<std::byte> &streamCache, std::size_t suggestedCount) const override + { + if(!suggestedCount|| !m_targetSize || m_broken) + return; + + uint32 remain = std::min(m_totalRemain, mpt::saturate_cast<uint32>(suggestedCount)); + + if(streamCache.empty()) + { + // Fist byte is always read verbatim + streamCache.reserve(std::min(m_targetSize, m_suggestedReserveSize)); + streamCache.push_back(mpt::byte_cast<std::byte>(file.ReadUint8())); + m_totalRemain--; remain--; - } else + } + + int32 strLen = m_strLen; + if(strLen) { - // a 1 ctrl bit means compressed bytes are following - uint8 lengthAdjust = 0; // length adjustment - DECODE_CTRL_BITS; // read length, and if strLen > 3 (coded using more than 1 bits pair) also part of the offset value - strLen -= 3; - if(strLen < 0) - { - // means LZ ptr with same previous relative LZ ptr (saved one) - strOffset = previousPtr; // restore previous Ptr - strLen++; - } else + // Previous string copy is still in progress + uint32 copyLen = std::min(static_cast<uint32>(strLen), remain); + m_totalRemain -= copyLen; + remain -= copyLen; + strLen -= copyLen; + streamCache.insert(streamCache.end(), copyLen, std::byte{}); + auto src = streamCache.cend() - copyLen + m_strOffset; + auto dst = streamCache.end() - copyLen; + do + { + copyLen--; + *dst++ = *src++; + } while(copyLen > 0); + } + + uint16 data = m_data; + int8 carry = 0; // x86 carry (used to propagate the most significant bit from one byte to another) + while(remain) + { + READ_CTRL_BIT; + if(!carry) { - // LZ ptr in ctrl stream - if(uint8 b; file.Read(b)) - strOffset = mpt::lshift_signed(strLen, 8) | b; // read less significant offset byte from stream + // a 0 ctrl bit means 'copy', not compressed byte + if(std::byte b; file.Read(b)) + streamCache.push_back(b); else break; - strLen = 0; - strOffset = ~strOffset; - if(strOffset < -1280) - lengthAdjust++; - lengthAdjust++; // length is always at least 1 - if(strOffset < -32000) - lengthAdjust++; - previousPtr = strOffset; // save current Ptr - } - - // read the next 2 bits as part of strLen - READ_CTRL_BIT; - strLen = mpt::lshift_signed(strLen, 1) + carry; - READ_CTRL_BIT; - strLen = mpt::lshift_signed(strLen, 1) + carry; - if(strLen == 0) + m_totalRemain--; + remain--; + } else { - // length does not fit in 2 bits - DECODE_CTRL_BITS; // decode length: 1 is the most significant bit, - strLen += 2; // then first bit of each bits pairs (noted n1), until n0. - } - strLen += lengthAdjust; // length adjustment + // a 1 ctrl bit means compressed bytes are following + uint8 lengthAdjust = 0; // length adjustment + DECODE_CTRL_BITS; // read length, and if strLen > 3 (coded using more than 1 bits pair) also part of the offset value + strLen -= 3; + if(strLen < 0) + { + // means LZ ptr with same previous relative LZ ptr (saved one) + m_strOffset = m_previousPtr; // restore previous Ptr + strLen++; + } else + { + // LZ ptr in ctrl stream + if(uint8 b; file.Read(b)) + m_strOffset = mpt::lshift_signed(strLen, 8) | b; // read less significant offset byte from stream + else + break; + strLen = 0; + m_strOffset = ~m_strOffset; + if(m_strOffset < -1280) + lengthAdjust++; + lengthAdjust++; // length is always at least 1 + if(m_strOffset < -32000) + lengthAdjust++; + m_previousPtr = m_strOffset; // save current Ptr + } - if(remain < static_cast<uint32>(strLen) || strLen <= 0) - break; - if(strOffset >= 0 || -static_cast<ptrdiff_t>(uncompressed.size()) > strOffset) - break; + // read the next 2 bits as part of strLen + READ_CTRL_BIT; + strLen = mpt::lshift_signed(strLen, 1) + carry; + READ_CTRL_BIT; + strLen = mpt::lshift_signed(strLen, 1) + carry; + if(strLen == 0) + { + // length does not fit in 2 bits + DECODE_CTRL_BITS; // decode length: 1 is the most significant bit, + strLen += 2; // then first bit of each bits pairs (noted n1), until n0. + } + strLen += lengthAdjust; // length adjustment - // Copy previous string - // Need to do this in two steps as source and destination may overlap (e.g. strOffset = -1, strLen = 2 repeats last character twice) - uncompressed.insert(uncompressed.end(), strLen, 0); - remain -= strLen; - auto src = uncompressed.cend() - strLen + strOffset; - auto dst = uncompressed.end() - strLen; - do - { - strLen--; - *dst++ = *src++; - } while(strLen > 0); + if(strLen <= 0 || m_totalRemain < static_cast<uint32>(strLen)) + break; + if(m_strOffset >= 0 || -static_cast<ptrdiff_t>(streamCache.size()) > m_strOffset) + break; + + // Copy previous string + // Need to do this in two steps (allocate, then copy) as source and destination may overlap (e.g. strOffset = -1, strLen = 2 repeats last character twice) + uint32 copyLen = std::min(static_cast<uint32>(strLen), remain); + m_totalRemain -= copyLen; + remain -= copyLen; + strLen -= copyLen; + streamCache.insert(streamCache.end(), copyLen, std::byte{}); + auto src = streamCache.cend() - copyLen + m_strOffset; + auto dst = streamCache.end() - copyLen; + do + { + copyLen--; + *dst++ = *src++; + } while(copyLen > 0); + } } + m_data = data; + m_strLen = strLen; + // Premature EOF or corrupted stream? + if(remain) + m_broken = true; } -#ifdef MPT_BUILD_FUZZER - // When using a fuzzer, we should not care if the decompressed buffer has the correct size. - // This makes finding new interesting test cases much easier. - return true; -#else - return remain == 0; -#endif // MPT_BUILD_FUZZER -} + + bool HasPinnedView() const override + { + return false; + } + + mutable FileReader file; + const uint32 m_suggestedReserveSize; + const uint32 m_targetSize; + mutable bool m_broken = false; + mutable uint16 m_data = 0; + mutable int32 m_strLen = 0; // Length of repeated string + mutable int32 m_strOffset = 0; // Offset of repeated string + mutable uint32 m_previousPtr = 0; + mutable uint32 m_totalRemain = 0; +}; struct MO3Delta8BitParams @@ -800,31 +867,23 @@ reserveSize = std::min(Util::MaxValueOfType(reserveSize) / 32u, compressedSize) * 32u; } - std::vector<uint8> musicData; - // We don't always reserve the whole uncompressed size as claimed by the module to guard against broken files - // that e.g. claim that the uncompressed size is 1GB while the MO3 file itself is only 100 bytes. - // As the LZ compression used in MO3 doesn't allow for establishing a clear upper bound for the maximum size, - // this is probably the only sensible way we can prevent DoS due to huge allocations. - musicData.reserve(std::min(reserveSize, containerHeader.musicSize.get())); - if(!UnpackMO3Data(file, musicData, containerHeader.musicSize)) - { - return false; - } - if(version >= 5) - { - file.Seek(12 + compressedSize); - } + std::shared_ptr<mpt::PathString> filenamePtr; + if(auto filename = file.GetOptionalFileName(); filename) + filenamePtr = std::make_shared<mpt::PathString>(std::move(*filename)); + auto musicChunkData = std::make_shared<MO3FileReaderBuffer>(file, containerHeader.musicSize, reserveSize); + mpt::IO::FileCursor<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>> fileCursor{musicChunkData, std::move(filenamePtr)}; + FileReader musicChunk{fileCursor}; InitializeGlobals(); InitializeChannels(); - FileReader musicChunk(mpt::as_span(musicData)); musicChunk.ReadNullString(m_songName); musicChunk.ReadNullString(m_songMessage); MO3FileHeader fileHeader; if(!musicChunk.ReadStruct(fileHeader) || fileHeader.numChannels == 0 || fileHeader.numChannels > MAX_BASECHANNELS + || fileHeader.restartPos > fileHeader.numOrders || fileHeader.numInstruments >= MAX_INSTRUMENTS || fileHeader.numSamples >= MAX_SAMPLES) { @@ -1247,7 +1306,8 @@ while(musicChunk.ReadUint8() != 0) ; } - musicChunk.Skip(sizeof(MO3Instrument)); + if(!musicChunk.Skip(sizeof(MO3Instrument))) + return false; continue; } @@ -1262,7 +1322,7 @@ MO3Instrument insHeader; if(!musicChunk.ReadStruct(insHeader)) - break; + return false; insHeader.ConvertToMPT(*pIns, m_nType); if(m_nType == MOD_TYPE_XM) @@ -1272,7 +1332,6 @@ m_nInstruments = 0; std::vector<MO3SampleInfo> sampleInfos; - const bool frequencyIsHertz = (version >= 5 || !(fileHeader.flags & MO3FileHeader::linearSlides)); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { @@ -1287,7 +1346,7 @@ MO3Sample smpHeader; if(!musicChunk.ReadStruct(smpHeader)) - break; + return false; smpHeader.ConvertToMPT(sample, m_nType, frequencyIsHertz); sample.filename = name; @@ -1516,6 +1575,17 @@ if(!(loadFlags & loadSampleData)) return true; + if(containerHeader.version < 5) + { + // As we don't know where the compressed data ends, we don't know where the sample data starts, either. + if(!musicChunkData->UnpackedSuccessfully()) + return false; + file.Seek(musicChunkData->SourcePosition()); + } else + { + file.Seek(12 + compressedSize); + } + bool unsupportedSamples = false; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { |
From: <sv...@op...> - 2024-04-16 13:27:46
|
Author: sagamusix Date: Tue Apr 16 15:27:34 2024 New Revision: 20609 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20609 Log: [Mod] MOD: 64 entries plus one loop point is of course 65 vector entries to reserve, not 64... Modified: trunk/OpenMPT/soundlib/Load_mod.cpp Modified: trunk/OpenMPT/soundlib/Load_mod.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp Tue Apr 16 09:53:13 2024 (r20608) +++ trunk/OpenMPT/soundlib/Load_mod.cpp Tue Apr 16 15:27:34 2024 (r20609) @@ -1387,7 +1387,7 @@ } auto &events = instr->synth.m_scripts.emplace_back(); - events.reserve(std::min(loopEnd + 1, 64)); + events.reserve(std::min(loopEnd + 1, 65)); const auto waveforms = file.ReadArray<uint8, 64>(); const auto volumes = file.ReadArray<uint8, 64>(); for(uint8 i = 0; i < 64; i++) |