From b4a7be695f3bff9158f12be16d1c514db27e4446 Mon Sep 17 00:00:00 2001 From: Persune Date: Tue, 16 May 2023 18:45:40 +0800 Subject: [PATCH 01/13] Avoid checking assert with unsigned integer cast This fixes #209. --- Source/FamiTrackerView.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/FamiTrackerView.cpp b/Source/FamiTrackerView.cpp index 53ae998e..f12c6697 100644 --- a/Source/FamiTrackerView.cpp +++ b/Source/FamiTrackerView.cpp @@ -1778,21 +1778,21 @@ void CFamiTrackerView::MoveCursorPrevChannel() void CFamiTrackerView::SelectFrame(unsigned int Frame) { - ASSERT(Frame < MAX_FRAMES); + ASSERT(static_cast(Frame) < MAX_FRAMES); // avoid comparing against UINT32_MAX m_pPatternEditor->MoveToFrame(Frame); InvalidateCursor(); } void CFamiTrackerView::SelectRow(unsigned int Row) { - ASSERT(Row < MAX_PATTERN_LENGTH); + ASSERT(static_cast(Row) < MAX_PATTERN_LENGTH); // avoid comparing against UINT32_MAX m_pPatternEditor->MoveToRow(Row); InvalidateCursor(); } void CFamiTrackerView::SelectChannel(unsigned int Channel) { - ASSERT(Channel < MAX_CHANNELS); + ASSERT(static_cast(Channel) < MAX_CHANNELS); // avoid comparing against UINT32_MAX m_pPatternEditor->MoveToChannel(Channel); InvalidateCursor(); } From e73d2e019bd77a5972e684102daa18bf0a2b8e71 Mon Sep 17 00:00:00 2001 From: Persune Date: Tue, 16 May 2023 22:16:29 +0800 Subject: [PATCH 02/13] Wait for APU mutex lock while rendering Thanks @nyanpasu64! --- Source/SoundGen.cpp | 68 ++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/Source/SoundGen.cpp b/Source/SoundGen.cpp index fea8e78d..31dfef7d 100644 --- a/Source/SoundGen.cpp +++ b/Source/SoundGen.cpp @@ -2407,41 +2407,51 @@ void CSoundGen::UpdateAPU() m_bInternalWaveChanged = m_bWaveChanged; m_bWaveChanged = false; - { - auto l = DeferLock(); - if (l.try_lock()) { - // Update APU channel registers - unsigned int PrevChip = SNDCHIP_NONE; // // // 050B - for (int i = 0; i < CHANNELS; ++i) { - if (m_pChannels[i] != NULL) { - m_pChannels[i]->RefreshChannel(); - m_pChannels[i]->FinishTick(); // // // - unsigned int Chip = m_pTrackerChannels[i]->GetChip(); - if (m_pDocument->ExpansionEnabled(Chip)) { - int Delay = (Chip == PrevChip) ? 150 : 250; - - AddCyclesUnlessEndOfFrame(Delay); - m_pAPU->Process(); - - PrevChip = Chip; - } + auto UpdateAPU = [&]() { + unsigned int PrevChip = SNDCHIP_NONE; // // // 050B + for (int i = 0; i < CHANNELS; ++i) { + if (m_pChannels[i] != NULL) { + m_pChannels[i]->RefreshChannel(); + m_pChannels[i]->FinishTick(); // // // + unsigned int Chip = m_pTrackerChannels[i]->GetChip(); + if (m_pDocument->ExpansionEnabled(Chip)) { + int Delay = (Chip == PrevChip) ? 150 : 250; + + AddCyclesUnlessEndOfFrame(Delay); + m_pAPU->Process(); + + PrevChip = Chip; } } - #ifdef WRITE_VGM // // // - if (m_bPlaying) - m_iRegisterStream.push(0x62); // // // - #endif - - // Finish the audio frame - if (m_iConsumedCycles > m_iUpdateCycles) { - throw std::runtime_error("overflowed vblank!"); - } + } +#ifdef WRITE_VGM // // // + if (m_bPlaying) + m_iRegisterStream.push(0x62); // // // +#endif - m_pAPU->AddCycles(m_iUpdateCycles - m_iConsumedCycles); - m_pAPU->Process(); + // Finish the audio frame + if (m_iConsumedCycles > m_iUpdateCycles) { + throw std::runtime_error("overflowed vblank!"); + } + m_pAPU->AddCycles(m_iUpdateCycles - m_iConsumedCycles); + m_pAPU->Process(); + }; + + { + if (m_bRendering) { + auto l = Lock(); + UpdateAPU(); l.unlock(); } + else { + auto l = DeferLock(); + if (l.try_lock()) { + UpdateAPU(); + l.unlock(); + } + else TRACE("SoundGen: APU mutex lock failed"); + } } m_iConsumedCycles = 0; From 8186e8141dec539f4f58d1d608edaa750c6d8b2d Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 31 May 2023 14:58:12 +0800 Subject: [PATCH 03/13] Assert legacy mixing levels and ranges This fixes #213. --- Source/APU/2A03.cpp | 12 ++++++------ Source/APU/2A03.h | 4 ++-- Source/APU/FDS.cpp | 7 +------ Source/APU/Mixer.cpp | 27 +++++++++++---------------- Source/APU/VRC7.cpp | 2 +- 5 files changed, 21 insertions(+), 31 deletions(-) diff --git a/Source/APU/2A03.cpp b/Source/APU/2A03.cpp index ad75845a..71de9cc2 100644 --- a/Source/APU/2A03.cpp +++ b/Source/APU/2A03.cpp @@ -198,16 +198,16 @@ int C2A03::GetChannelLevelRange(int Channel) const } -void C2A03::UpdateMixingAPU1(double v) { +void C2A03::UpdateMixingAPU1(double v, bool UseSurveyMix) { // NSFPlay output waveform ranges from 0 - 8191 - // should not affect legacy mixing - Synth2A03SS.volume(v, 8191); + // legacy mixing absolutely requires the range 10000 + Synth2A03SS.volume(v, UseSurveyMix ? 8191 : 10000); } -void C2A03::UpdateMixingAPU2(double v) { +void C2A03::UpdateMixingAPU2(double v, bool UseSurveyMix) { // NSFPlay output waveform ranges from 0 - 8191 - // should not affect legacy mixing - Synth2A03TND.volume(v, 8191); + // legacy mixing absolutely requires the range 10000 + Synth2A03TND.volume(v, UseSurveyMix ? 8191 : 10000); } void C2A03::ClockSequence() diff --git a/Source/APU/2A03.h b/Source/APU/2A03.h index 08ebb3ff..38a03586 100644 --- a/Source/APU/2A03.h +++ b/Source/APU/2A03.h @@ -99,8 +99,8 @@ class C2A03 : public CSoundChip2 int GetChannelLevelRange(int Channel) const override; public: - void UpdateMixingAPU1(double v); - void UpdateMixingAPU2(double v); + void UpdateMixingAPU1(double v, bool UseSurveyMix = false); + void UpdateMixingAPU2(double v, bool UseSurveyMix = false); void ClockSequence(); // // // diff --git a/Source/APU/FDS.cpp b/Source/APU/FDS.cpp index 230c3b13..9a8451c5 100644 --- a/Source/APU/FDS.cpp +++ b/Source/APU/FDS.cpp @@ -232,12 +232,7 @@ void CFDS::UpdateMixLevel(double v, bool UseSurveyMix) // (m_SynthFDS: FdsAudio) used to generate output samples between [0..63] inclusive, // but was changed to [0 .. 63*1152] inclusive to prevent quantization at low volumes. - if (UseSurveyMix) - m_SynthFDS.volume(v, 63 * 1152); - else - // The following mixing levels match nsfplay's FDS output, - // using 2A03 Pulse as a baseline. - m_SynthFDS.volume(v * 1.122f, 256 * 1152); + m_SynthFDS.volume(UseSurveyMix ? v : (v * 1.122f), UseSurveyMix ? (63 * 1152) : (256 * 1152)); } /// Input: diff --git a/Source/APU/Mixer.cpp b/Source/APU/Mixer.cpp index 42985d38..37f2885d 100644 --- a/Source/APU/Mixer.cpp +++ b/Source/APU/Mixer.cpp @@ -148,7 +148,7 @@ void CMixer::SetChipLevel(chip_level_t Chip, float Level) float CMixer::GetAttenuation(bool UseSurveyMix) const { - float Attenuation = 1.0f; + float ATTENUATION_2A03 = 1.0f; if (!UseSurveyMix) { const float ATTENUATION_VRC6 = 0.80f; @@ -161,22 +161,17 @@ float CMixer::GetAttenuation(bool UseSurveyMix) const // Increase headroom if some expansion chips are enabled if (m_iExternalChip & SNDCHIP_VRC6) - Attenuation *= ATTENUATION_VRC6; - + ATTENUATION_2A03 *= ATTENUATION_VRC6; if (m_iExternalChip & SNDCHIP_VRC7) - Attenuation *= ATTENUATION_VRC7; - + ATTENUATION_2A03 *= ATTENUATION_VRC7; if (m_iExternalChip & SNDCHIP_FDS) - Attenuation *= ATTENUATION_FDS; - + ATTENUATION_2A03 *= ATTENUATION_FDS; if (m_iExternalChip & SNDCHIP_MMC5) - Attenuation *= ATTENUATION_MMC5; - + ATTENUATION_2A03 *= ATTENUATION_MMC5; if (m_iExternalChip & SNDCHIP_N163) - Attenuation *= ATTENUATION_N163; - + ATTENUATION_2A03 *= ATTENUATION_N163; if (m_iExternalChip & SNDCHIP_S5B) // // // 050B - Attenuation *= ATTENUATION_S5B; + ATTENUATION_2A03 *= ATTENUATION_S5B; } else { // attenuation scaling is exponential based on total chips used @@ -188,10 +183,10 @@ float CMixer::GetAttenuation(bool UseSurveyMix) const if (m_iExternalChip & SNDCHIP_N163) TotalChipsUsed++; if (m_iExternalChip & SNDCHIP_S5B) TotalChipsUsed++; - Attenuation *= static_cast(1.0 / (float)TotalChipsUsed); + ATTENUATION_2A03 *= static_cast(1.0 / (float)TotalChipsUsed); } - return Attenuation; + return ATTENUATION_2A03; } void CMixer::RecomputeEmuMixState() @@ -229,8 +224,8 @@ void CMixer::RecomputeEmuMixState() // Maybe the range argument, as well as the constant factor in the volume, // should be supplied by the CSoundChip2 subclass rather than CMixer. - chip2A03.UpdateMixingAPU1(Volume * m_fLevelAPU1); - chip2A03.UpdateMixingAPU2(Volume * m_fLevelAPU2); + chip2A03.UpdateMixingAPU1(Volume * m_fLevelAPU1, UseSurveyMixing); + chip2A03.UpdateMixingAPU2(Volume * m_fLevelAPU2, UseSurveyMixing); chipFDS.UpdateMixLevel(Volume * m_fLevelFDS, UseSurveyMixing); chipN163.UpdateMixLevel(Volume * m_fLevelN163, UseSurveyMixing); diff --git a/Source/APU/VRC7.cpp b/Source/APU/VRC7.cpp index 880304ea..b86b80f8 100644 --- a/Source/APU/VRC7.cpp +++ b/Source/APU/VRC7.cpp @@ -203,7 +203,7 @@ void CVRC7::UpdateMixLevel(double v, bool UseSurveyMix) SetDirectVolume(UseSurveyMix ? v : (v * AMPLIFY)); // emu2413's waveform output ranges from -4095...4095 - m_SynthVRC7.volume(v, 8191); + m_SynthVRC7.volume(v, UseSurveyMix ? 8191 : 10000); } void CVRC7::UpdatePatchSet(int PatchSelection, bool UseExternalOPLLChip, uint8_t* PatchSet) From 7dc78be9b4c224aa9ca23b72cd5b58ac341a0233 Mon Sep 17 00:00:00 2001 From: Persune Date: Tue, 1 Aug 2023 19:31:57 +0800 Subject: [PATCH 04/13] Fix detune offset direction This fixes #225. - Refactor and annotate tuning definitions --- Source/DetuneTable.cpp | 32 +++++++++++++++++++++++++------- Source/SoundGen.cpp | 6 +++--- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Source/DetuneTable.cpp b/Source/DetuneTable.cpp index 1946db2d..c69bac09 100644 --- a/Source/DetuneTable.cpp +++ b/Source/DetuneTable.cpp @@ -118,6 +118,8 @@ double CDetuneTable::PeriodToFrequency(unsigned int Period, int Octave, int Namc return 0.0; } +// https://www.nesdev.org/wiki/APU_Pulse#Sequencer_behavior +// no compensation is done for triangle CDetuneNTSC::CDetuneNTSC(double A440_Note) : CDetuneTable(DETUNE_NTSC, 0, 0x7FF, A440_Note) { @@ -126,16 +128,19 @@ CDetuneNTSC::CDetuneNTSC(double A440_Note) : GenerateRegisters(); } +// period = CPU_clk / (16 * frequency) - 1 unsigned int CDetuneNTSC::FrequencyToPeriod(double Freq, int Octave, int NamcoChannels) const { return std::lround((CAPU::BASE_FREQ_NTSC / (Freq * 16.0)) - 1.0); } +// frequency = CPU_clk / 16 * (period + 1) double CDetuneNTSC::PeriodToFrequency(unsigned int Period, int Octave, int NamcoChannels) const { - return CAPU::BASE_FREQ_NTSC / (16.0 * (Period + 1.0)); + return CAPU::BASE_FREQ_NTSC / (16.0 * ((double)Period + 1.0)); } +// same as CDetuneNTSC, but with different clock frequency CDetunePAL::CDetunePAL(double A440_Note) : CDetuneTable(DETUNE_PAL, 0, 0x7FF, A440_Note) { @@ -151,9 +156,10 @@ unsigned int CDetunePAL::FrequencyToPeriod(double Freq, int Octave, int NamcoCha double CDetunePAL::PeriodToFrequency(unsigned int Period, int Octave, int NamcoChannels) const { - return CAPU::BASE_FREQ_PAL / (16.0 * (Period + 1.0)); + return CAPU::BASE_FREQ_PAL / (16.0 * ((double)Period + 1.0)); } +// https://www.nesdev.org/wiki/VRC6_audio#Sawtooth_Channel CDetuneSaw::CDetuneSaw(double A440_Note) : CDetuneTable(DETUNE_SAW, 0, 0xFFF, A440_Note) { @@ -162,16 +168,19 @@ CDetuneSaw::CDetuneSaw(double A440_Note) : GenerateRegisters(); } +// period = (CPU_clk / (14 * frequency)) - 1 unsigned int CDetuneSaw::FrequencyToPeriod(double Freq, int Octave, int NamcoChannels) const { return std::lround((CAPU::BASE_FREQ_NTSC / (Freq * 14.0)) - 1.0); } +// frequency = CPU_clk / (14 * (period + 1)) double CDetuneSaw::PeriodToFrequency(unsigned int Period, int Octave, int NamcoChannels) const { - return CAPU::BASE_FREQ_NTSC / (14.0 * (Period + 1.0)); + return CAPU::BASE_FREQ_NTSC / (14.0 * ((double)Period + 1.0)); } +// https://www.nesdev.org/wiki/VRC7_audio#Channels CDetuneVRC7::CDetuneVRC7(double A440_Note) : CDetuneTable(DETUNE_VRC7, 0, 0x1FF, A440_Note) { @@ -186,9 +195,10 @@ unsigned int CDetuneVRC7::FrequencyToPeriod(double Freq, int Octave, int NamcoCh return std::lround((Freq * std::pow(2, (19 - Octave))) / (CAPU::BASE_FREQ_VRC7 / 72.0)); } +// frequency = (VRC7_Xclock / 72 * period) / 2^(19 - octave - 1) double CDetuneVRC7::PeriodToFrequency(unsigned int Period, int Octave, int NamcoChannels) const { - return ((CAPU::BASE_FREQ_VRC7 / 72.0) * Period) / std::pow(2, (19 - Octave - 1)); + return ((CAPU::BASE_FREQ_VRC7 / 72.0) * (double)Period) / std::pow(2, (19 - Octave - 1)); } CDetuneFDS::CDetuneFDS(double A440_Note) : @@ -209,6 +219,7 @@ double CDetuneFDS::PeriodToFrequency(unsigned int Period, int Octave, int NamcoC return (CAPU::BASE_FREQ_NTSC * (double)Period) / (65536.0); } +// https://www.nesdev.org/wiki/Namco_163_audio#Frequency CDetuneN163::CDetuneN163(double A440_Note) : CDetuneTable(DETUNE_N163, 0, 0xFFFF, A440_Note), m_iChannelCount(1) @@ -218,14 +229,16 @@ CDetuneN163::CDetuneN163(double A440_Note) : GenerateRegisters(); } +// period = (frequency * 15 * (65536 * 4) * channel_count) / CPU_clk unsigned int CDetuneN163::FrequencyToPeriod(double Freq, int Octave, int NamcoChannels) const { - return std::lround((Freq * 15.0 * 65536.0 * 4.0 * NamcoChannels) / (CAPU::BASE_FREQ_NTSC)); + return std::lround((Freq * 15.0 * 262144.0 * NamcoChannels) / CAPU::BASE_FREQ_NTSC); } +// frequency = (CPU_clk * period) / (15 * (65536 * 4) * channel_count) double CDetuneN163::PeriodToFrequency(unsigned int Period, int Octave, int NamcoChannels) const { - return std::lround((Period * 15.0 * 65536.0 * 4.0 * NamcoChannels) / (CAPU::BASE_FREQ_NTSC)); + return std::lround((CAPU::BASE_FREQ_NTSC * (double)Period) / (15.0 * 262144.0 * NamcoChannels)); } void CDetuneN163::SetChannelCount(unsigned Count) // special @@ -233,6 +246,7 @@ void CDetuneN163::SetChannelCount(unsigned Count) // special m_iChannelCount = Count; } +// https://www.nesdev.org/wiki/Sunsoft_5B_audio#Sound CDetuneS5B::CDetuneS5B(double A440_Note) : CDetuneTable(DETUNE_S5B, 0, 0xFFF, A440_Note) { @@ -241,12 +255,16 @@ CDetuneS5B::CDetuneS5B(double A440_Note) : GenerateRegisters(); } +// in the driver, S5B's note LUT uses the regular NTSC note LUT +- 1, since it's off-by-one +// so for compatibility, the frequency is doubled +// period = CPU_clk / (frequency * 16) unsigned int CDetuneS5B::FrequencyToPeriod(double Freq, int Octave, int NamcoChannels) const { return std::lround(CAPU::BASE_FREQ_NTSC / (Freq * 16.0)); } +// frequency = CPU_clk / (16 * period) double CDetuneS5B::PeriodToFrequency(unsigned int Period, int Octave, int NamcoChannels) const { - return CAPU::BASE_FREQ_NTSC / (16.0 * (Period)); + return CAPU::BASE_FREQ_NTSC / (16.0 * ((double)Period)); } diff --git a/Source/SoundGen.cpp b/Source/SoundGen.cpp index 31dfef7d..e2fb61cf 100644 --- a/Source/SoundGen.cpp +++ b/Source/SoundGen.cpp @@ -456,7 +456,7 @@ void CSoundGen::DocumentPropertiesChanged(CFamiTrackerDoc *pDocument) // // // VRC7 if (i < NOTE_RANGE) { Pitch = pDetuneVRC7->FrequencyToPeriod(pDetuneVRC7->NoteToFreq(i), 1, 0); - m_iNoteLookupTableVRC7[i] = std::lround(Pitch - pDocument->GetDetuneOffset(3, i)); // // // + m_iNoteLookupTableVRC7[i] = std::lround(Pitch + pDocument->GetDetuneOffset(3, i)); // // // } // FDS @@ -465,11 +465,11 @@ void CSoundGen::DocumentPropertiesChanged(CFamiTrackerDoc *pDocument) #else Pitch = (NoteToFreq(i) * 65536.0) / (clock_ntsc / 4.0); #endif - m_iNoteLookupTableFDS[i] = std::lround(Pitch - pDocument->GetDetuneOffset(4, i)); // // // + m_iNoteLookupTableFDS[i] = std::lround(Pitch + pDocument->GetDetuneOffset(4, i)); // // // // N163 Pitch = pDetuneN163->FrequencyToPeriod(pDetuneN163->NoteToFreq(i), 1, pDocument->GetNamcoChannels()); - m_iNoteLookupTableN163[i] = std::lround(Pitch - pDocument->GetDetuneOffset(5, i)); // // // + m_iNoteLookupTableN163[i] = std::lround(Pitch + pDocument->GetDetuneOffset(5, i)); // // // if (m_iNoteLookupTableN163[i] > 0xFFFF) // 0x3FFFF m_iNoteLookupTableN163[i] = 0xFFFF; // 0x3FFFF From 82aa980b57bf162112a39fb115513cd91a3bc551 Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 2 Aug 2023 00:45:29 +0800 Subject: [PATCH 05/13] Fix incorrect speed in PAL exports Fixes #223. --- Source/Compiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Compiler.cpp b/Source/Compiler.cpp index 260106b8..2c8ac43c 100644 --- a/Source/Compiler.cpp +++ b/Source/Compiler.cpp @@ -1482,7 +1482,7 @@ void CCompiler::CreateHeader(stNSFHeader *pHeader, int MachineType, unsigned int // If speed is default, write correct NTSC/PAL speed periods // else, set the same custom speed for both SpeedNTSC = (Speed == 0) ? 1000000 / CAPU::FRAME_RATE_NTSC : 1000000 / Speed; - SpeedPAL = (Speed == 0) ? 1000000 / CAPU::FRAME_RATE_NTSC : 1000000 / Speed; + SpeedPAL = (Speed == 0) ? 1000000 / CAPU::FRAME_RATE_PAL : 1000000 / Speed; memset(pHeader, 0, 0x80); @@ -1564,7 +1564,7 @@ void CCompiler::CreateNSFeHeader(stNSFeHeader *pHeader, int MachineType) // // unsigned int SpeedPAL, SpeedNTSC, Speed; Speed = m_pDocument->GetEngineSpeed(); SpeedNTSC = (Speed == 0) ? 1000000 / CAPU::FRAME_RATE_NTSC : 1000000 / Speed; - SpeedPAL = (Speed == 0) ? 1000000 / CAPU::FRAME_RATE_NTSC : 1000000 / Speed; + SpeedPAL = (Speed == 0) ? 1000000 / CAPU::FRAME_RATE_PAL : 1000000 / Speed; pHeader->InfoSize = 12; pHeader->BankSize = 8; From 43b1d528fd0a31eaee6fe0fd83ba9ba9d1c514ea Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 29 Nov 2023 01:46:27 +0800 Subject: [PATCH 06/13] Fix access violation in MRU submenu list update Fixes #243. --- Source/FamiTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FamiTracker.cpp b/Source/FamiTracker.cpp index 9f86d091..50d046ad 100644 --- a/Source/FamiTracker.cpp +++ b/Source/FamiTracker.cpp @@ -455,11 +455,11 @@ void CFamiTrackerApp::OnRecentFilesClear() // // // void CFamiTrackerApp::OnUpdateRecentFiles(CCmdUI *pCmdUI) // // // { - // https://www.codeguru.com/cpp/controls/menu/miscellaneous/article.php/c167 + // https://web.archive.org/web/20190906190854/https://www.codeguru.com/cpp/controls/menu/miscellaneous/article.php/c167/MRU-list-in-a-submenu-the-MFC-bug-and-how-to-correct-it.htm // updating a submenu? if (pCmdUI->m_pSubMenu != NULL) return; - m_pRecentFileList->UpdateMenu(pCmdUI); + CWinApp::OnUpdateRecentFileMenu(pCmdUI); } void CFamiTrackerApp::ShutDownSynth() From ef20dda2266dcdea509fd398ad3cb01205b7b87f Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 29 Nov 2023 01:54:04 +0800 Subject: [PATCH 07/13] Fix narrowing conversion bug --- Source/FrameAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/FrameAction.cpp b/Source/FrameAction.cpp index a88b651e..b85305f8 100644 --- a/Source/FrameAction.cpp +++ b/Source/FrameAction.cpp @@ -34,7 +34,7 @@ CFrameEditorState::CFrameEditorState(const CFamiTrackerView *pView, int Track) : // // // Track(Track), - Cursor {static_cast(pView->GetParentFrame())->GetFrameEditor()->GetEditFrame(), (int)pView->GetSelectedChannel()}, + Cursor{ static_cast(pView->GetParentFrame())->GetFrameEditor()->GetEditFrame(), static_cast(pView->GetSelectedChannel()) }, OriginalSelection(static_cast(pView->GetParentFrame())->GetFrameEditor()->GetSelection()), IsSelecting(static_cast(pView->GetParentFrame())->GetFrameEditor()->IsSelecting()) { From 4cdacd92af4500e2d2d5d9800da5b9ba03ea8505 Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 29 Nov 2023 21:01:06 +0800 Subject: [PATCH 08/13] Avoid division by zero in MML sequence parsing Fixes #222. --- Source/SequenceParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SequenceParser.cpp b/Source/SequenceParser.cpp index 7fa42799..a01e73a9 100644 --- a/Source/SequenceParser.cpp +++ b/Source/SequenceParser.cpp @@ -65,7 +65,7 @@ bool CSeqConversionDefault::ToValue(const std::string &String) if (!GetNextInteger(b, e, m_iRepeat)) return false; } - if (b != e || m_iRepeat <= 0) + if (b != e || m_iRepeat <= 0 || m_iValueDiv <= 0) return false; m_iValueInc = m_iTargetValue - m_iCurrentValue; m_iRepeatCounter = m_iCounter = m_iValueMod = 0; From f6b08cdd5ef946b27454ad25316c62b675ea937a Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 29 Nov 2023 22:18:39 +0800 Subject: [PATCH 09/13] Fix numpad effect number input Fixes #48. --- Source/FamiTrackerView.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/FamiTrackerView.cpp b/Source/FamiTrackerView.cpp index f12c6697..7b61e31b 100644 --- a/Source/FamiTrackerView.cpp +++ b/Source/FamiTrackerView.cpp @@ -2973,9 +2973,6 @@ bool CFamiTrackerView::EditEffNumberColumn(stChanNote &Note, Input input, int Ef bStepDown = true; return true; } - - if (key >= VK_NUMPAD0 && key <= VK_NUMPAD9) - key = '0' + (key - VK_NUMPAD0); } CFamiTrackerDoc* pDoc = GetDocument(); @@ -2990,6 +2987,10 @@ bool CFamiTrackerView::EditEffNumberColumn(stChanNote &Note, Input input, int Ef if (auto p = get_if(&input)) { auto key = *p; + + if (key >= VK_NUMPAD0 && key <= VK_NUMPAD9) + key = '0' + (key - VK_NUMPAD0); + if (!isAlphanumeric(key)) { return false; } From 1bdd371d8aa69f5bd524ee2f7aa94819968aa793 Mon Sep 17 00:00:00 2001 From: Persune Date: Wed, 29 Nov 2023 22:37:04 +0800 Subject: [PATCH 10/13] Disable Custom Exporter DLL loading Fixes #232. --- Source/ExportDialog.cpp | 10 +++++++--- Source/FamiTracker.cpp | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/ExportDialog.cpp b/Source/ExportDialog.cpp index b3adadfe..7c93cadd 100644 --- a/Source/ExportDialog.cpp +++ b/Source/ExportDialog.cpp @@ -166,10 +166,14 @@ BOOL CExportDialog::OnInitDialog() // Add selections for each custom plugin name CStringArray names; - theApp.GetCustomExporters()->GetNames( names ); + CCustomExporters* pExporters = theApp.GetCustomExporters(); - for( int i = 0; i < names.GetCount(); ++i ) - pTypeBox->AddString( names[ i ] ); + if (pExporters) { + pExporters->GetNames(names); + + for (int i = 0; i < names.GetCount(); ++i) + pTypeBox->AddString(names[i]); + } // Set default selection pTypeBox->SetCurSel(m_iExportOption); diff --git a/Source/FamiTracker.cpp b/Source/FamiTracker.cpp index 50d046ad..df5f66cd 100644 --- a/Source/FamiTracker.cpp +++ b/Source/FamiTracker.cpp @@ -159,7 +159,11 @@ BOOL CFamiTrackerApp::InitInstance() GetModuleFileName(NULL, pathToPlugins, MAX_PATH); PathRemoveFileSpec(pathToPlugins); PathAppend(pathToPlugins, _T("\\Plugins")); - m_customExporters = new CCustomExporters( pathToPlugins ); + + // https://github.com/eatscrayon/Dn-FamiTracker-dll-hijack + // custom exporters are disabled until a better method is found. + // this is a huge security risk! + //m_customExporters = new CCustomExporters( pathToPlugins ); // Load custom accelerator m_pAccel = new CAccelerator(); From 6be25b047f150f7547384dd6f563707fe5b6da61 Mon Sep 17 00:00:00 2001 From: Persune Date: Tue, 12 Dec 2023 15:42:30 +0800 Subject: [PATCH 11/13] Avoid printing in empty JSON block text export --- Source/SoundGen.cpp | 2 +- Source/TextExporter.cpp | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Source/SoundGen.cpp b/Source/SoundGen.cpp index e2fb61cf..bc64a275 100644 --- a/Source/SoundGen.cpp +++ b/Source/SoundGen.cpp @@ -2450,7 +2450,7 @@ void CSoundGen::UpdateAPU() UpdateAPU(); l.unlock(); } - else TRACE("SoundGen: APU mutex lock failed"); + else TRACE("SoundGen: APU mutex lock failed\n"); } } diff --git a/Source/TextExporter.cpp b/Source/TextExporter.cpp index da570a6e..00f98bc7 100644 --- a/Source/TextExporter.cpp +++ b/Source/TextExporter.cpp @@ -1743,16 +1743,18 @@ const CString& CTextExport::ExportFile(LPCTSTR FileName, CFamiTrackerDoc *pDoc) f.WriteString(_T("# JSON block\n")); { json j = pDoc->InterfaceToOptionalJSON(); - std::string &jsondump = j.dump(4, ' ', true); - std::string &delimiter = std::string("\n"); - std::string::size_type pos = 0, prev = 0; - while ((pos = jsondump.find(delimiter, prev)) != std::string::npos) { - s.Format(_T("%s %s\n"), CT[CT_JSON], ExportString(jsondump.substr(prev, pos - prev).c_str())); + if (!j.is_null()) { + std::string& jsondump = j.dump(4, ' ', true); + std::string& delimiter = std::string("\n"); + std::string::size_type pos = 0, prev = 0; + while ((pos = jsondump.find(delimiter, prev)) != std::string::npos) { + s.Format(_T("%s %s\n"), CT[CT_JSON], ExportString(jsondump.substr(prev, pos - prev).c_str())); + f.WriteString(s); + prev = pos + delimiter.size(); + } + s.Format(_T("%s %s\n"), CT[CT_JSON], ExportString(jsondump.substr(prev).c_str())); f.WriteString(s); - prev = pos + delimiter.size(); } - s.Format(_T("%s %s\n"), CT[CT_JSON], ExportString(jsondump.substr(prev).c_str())); - f.WriteString(s); } f.WriteString(_T("\n")); From 517b4f0a26297353977f06e877678ffcaecb3217 Mon Sep 17 00:00:00 2001 From: Persune Date: Fri, 22 Dec 2023 12:16:23 +0800 Subject: [PATCH 12/13] Rename lambda to UpdateAPUImpl --- Source/SoundGen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/SoundGen.cpp b/Source/SoundGen.cpp index bc64a275..fd55ef88 100644 --- a/Source/SoundGen.cpp +++ b/Source/SoundGen.cpp @@ -2407,7 +2407,7 @@ void CSoundGen::UpdateAPU() m_bInternalWaveChanged = m_bWaveChanged; m_bWaveChanged = false; - auto UpdateAPU = [&]() { + auto UpdateAPUImpl = [&]() { unsigned int PrevChip = SNDCHIP_NONE; // // // 050B for (int i = 0; i < CHANNELS; ++i) { if (m_pChannels[i] != NULL) { @@ -2441,13 +2441,13 @@ void CSoundGen::UpdateAPU() { if (m_bRendering) { auto l = Lock(); - UpdateAPU(); + UpdateAPUImpl(); l.unlock(); } else { auto l = DeferLock(); if (l.try_lock()) { - UpdateAPU(); + UpdateAPUImpl(); l.unlock(); } else TRACE("SoundGen: APU mutex lock failed\n"); From 254814e01cfefd15af854112ceaae23304e4fa4f Mon Sep 17 00:00:00 2001 From: Persune Date: Fri, 22 Dec 2023 20:09:19 +0800 Subject: [PATCH 13/13] Force modules to be saved as Dn-FT modules This prevents modules to be saved with version 0x450 but without the Dn-FT specific file header, causing the program to interpret it as FT 050b modules instead. --- Source/FamiTrackerDoc.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/FamiTrackerDoc.cpp b/Source/FamiTrackerDoc.cpp index 2eb0b3c0..9a4b9602 100644 --- a/Source/FamiTrackerDoc.cpp +++ b/Source/FamiTrackerDoc.cpp @@ -391,8 +391,7 @@ BOOL CFamiTrackerDoc::OnSaveDocument(LPCTSTR lpszPathName) // TODO: Dn-FamiTracker compatibility modes // to avoid conflicts with FamiTracker beta 0.5.0 modules, set as Dn-FT module - if (m_iFileVersion >= 0x450U) - m_bFileDnModule = true; + m_bFileDnModule = true; if (!SaveDocument(lpszPathName)) return FALSE; @@ -816,7 +815,7 @@ bool CFamiTrackerDoc::WriteBlocks(CDocumentFile *pDocFile) const // internal 6, // Parameters 1, // Song Info - 1, // Tuning + 0, // Tuning 3, // Header 6, // Instruments 6, // Sequences @@ -827,6 +826,7 @@ bool CFamiTrackerDoc::WriteBlocks(CDocumentFile *pDocFile) const #else 6, // Parameters 1, // Song Info + 0, // Tuning 3, // Header 6, // Instruments 6, // Sequences @@ -872,8 +872,9 @@ bool CFamiTrackerDoc::WriteBlocks(CDocumentFile *pDocFile) const }; for (size_t i = 0; i < sizeof(FTM_WRITE_FUNC) / sizeof(*FTM_WRITE_FUNC); ++i) { - if (!CALL_MEMBER_FN(this, FTM_WRITE_FUNC[i])(pDocFile, DEFAULT_BLOCK_VERSION[i])) - return false; + if (DEFAULT_BLOCK_VERSION[i] != 0) // !! !! check if block version is nonzero + if (!CALL_MEMBER_FN(this, FTM_WRITE_FUNC[i])(pDocFile, DEFAULT_BLOCK_VERSION[i])) + return false; } return true; }