Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ Written by D.P.C.M.

Version 0.5.2.9

Last updated: January 06, 2026
Last updated: January 07, 2026

---

## Unreleased - 2026-01-06
## Unreleased - 2026-01-07

### Important changes

Expand All @@ -22,7 +22,11 @@ Last updated: January 06, 2026

### Bug fixes

- ...
- Revert "Fix C-0 not previewing DPCM sample" (@damifortune @Gumball2415 #383 #394)
- This reverts commit ac2648491c25473f0cc8c01ce8ef4cb09e9332c1.
- There doesn't seem to be any bug at the time of its writing upon further scrutiny.
- Separate tempo state updating from channel state updating (@JG540 @Gumball2415 #382 #384 #394)
- Set `m_iSpeed` to default when groove is enabled (@TakuikaNinja @Gumball2415 #379 #394)

### Internal

Expand Down
2 changes: 1 addition & 1 deletion Source/InstrumentEditorDPCM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ void CInstrumentEditorDPCM::OnNMClickTable(NMHDR *pNMHDR, LRESULT *pResult)
m_iSelectedKey = GET_NOTE(pTableListCtrl->GetSelectionMark()) - 1; // // //
m_iOctave = GET_OCTAVE(pTableListCtrl->GetSelectionMark());

int Sample = m_pInstrument->GetSampleIndex(m_iOctave, m_iSelectedKey);
int Sample = m_pInstrument->GetSampleIndex(m_iOctave, m_iSelectedKey) - 1;
int Pitch = m_pInstrument->GetSamplePitch(m_iOctave, m_iSelectedKey);
int Delta = m_pInstrument->GetSampleDeltaValue(m_iOctave, m_iSelectedKey);

Expand Down
61 changes: 41 additions & 20 deletions Source/SoundGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "FamiTracker.h"
#include "FamiTrackerTypes.h"
#include "FTMComponentInterface.h" // // //
#include "ChannelState.h" // // //
#include "FamiTrackerDoc.h"
#include "FamiTrackerView.h"
#include "VisualizerWnd.h"
Expand Down Expand Up @@ -1527,32 +1526,41 @@ void CSoundGen::ApplyGlobalState() // // //
int Frame = IsPlaying() ? GetPlayerFrame() : m_pTrackerView->GetSelectedFrame();
int Row = IsPlaying() ? GetPlayerRow() : m_pTrackerView->GetSelectedRow();
if (stFullState *State = m_pDocument->RetrieveSoundState(GetPlayerTrack(), Frame, Row, -1)) {
if (State->Tempo != -1)
m_iTempo = State->Tempo;
if (State->GroovePos >= 0) {
m_iGroovePosition = State->GroovePos;
if (State->Speed >= 0)
m_iGrooveIndex = State->Speed;
if (m_pDocument->GetGroove(m_iGrooveIndex) != NULL)
m_iSpeed = m_pDocument->GetGroove(m_iGrooveIndex)->GetEntry(m_iGroovePosition);
}
else {
if (State->Speed >= 0)
m_iSpeed = State->Speed;
m_iGrooveIndex = -1;
}
m_iLastHighlight = m_pDocument->GetHighlightAt(GetPlayerTrack(), Frame, Row).First;
ApplyGlobalTempoState(State);
SetupSpeed();
m_iLastHighlight = m_pDocument->GetHighlightAt(GetPlayerTrack(), Frame, Row).First;

for (int i = 0; i < m_pDocument->GetChannelCount(); i++) {
for (int j = 0; j < sizeof(m_pTrackerChannels) / sizeof(CTrackerChannel*); ++j) // // // pick this out later
if (m_pChannels[j] && m_pTrackerChannels[j]->GetID() == State->State[i].ChannelIndex) {
m_pChannels[j]->ApplyChannelState(&State->State[i]); break;
}
}

delete State;
}
}

// Separate updating groove, tempo and speed
// to allow ResetTempo() to get the most recent state without updating the channel state
void CSoundGen::ApplyGlobalTempoState(stFullState *pState)
{
if (pState->Tempo != -1)
m_iTempo = pState->Tempo;
if (pState->GroovePos >= 0) {
m_iGroovePosition = pState->GroovePos;
if (pState->Speed >= 0)
m_iGrooveIndex = pState->Speed;
if (m_pDocument->GetGroove(m_iGrooveIndex) != NULL)
m_iSpeed = m_pDocument->GetGroove(m_iGrooveIndex)->GetEntry(m_iGroovePosition);
}
else {
if (pState->Speed >= 0)
m_iSpeed = pState->Speed;
m_iGrooveIndex = -1;
}
}

/*! \brief Obtains a human-readable form of a channel state object.
\warning The output of this method is neither guaranteed nor required to match that of
CChannelHandler::GetStateString.
Expand Down Expand Up @@ -1858,10 +1866,23 @@ void CSoundGen::ResetTempo()

m_iTempoAccum = 0;

if (theApp.GetSettings()->General.bRetrieveChanState) // // //
ApplyGlobalState();
// Legacy behavior
if (theApp.GetSettings()->General.bRetrieveChanState) { // !! !!
// Calling on ApplyGlobalState() causes crackly audio on FDS
// May have something to do with conflicting stFullState pointers? haven't investigated
// So we do a reduced version here where we don't update the channel handlers.
int Frame = IsPlaying() ? GetPlayerFrame() : m_pTrackerView->GetSelectedFrame();
int Row = IsPlaying() ? GetPlayerRow() : m_pTrackerView->GetSelectedRow();
if (stFullState *State = m_pDocument->RetrieveSoundState(GetPlayerTrack(), Frame, Row, -1)) {
ApplyGlobalTempoState(State);
// Set m_iSpeed to avoid division by zero in SetupSpeed()
if (m_pDocument->GetSongGroove(m_iPlayTrack) && m_pDocument->GetGroove(m_iSpeed) == NULL)
m_iSpeed = DEFAULT_SPEED;
m_iLastHighlight = m_pDocument->GetHighlightAt(GetPlayerTrack(), Frame, Row).First;
delete State;
}
}
else {
// Legacy behavior
if (m_pDocument->GetSongGroove(m_iPlayTrack) && m_pDocument->GetGroove(m_iSpeed) != NULL) { // // //
m_iGrooveIndex = m_iSpeed;
m_iGroovePosition = 0;
Expand All @@ -1873,8 +1894,8 @@ void CSoundGen::ResetTempo()
if (m_pDocument->GetSongGroove(m_iPlayTrack))
m_iSpeed = DEFAULT_SPEED;
}
SetupSpeed();
}
SetupSpeed();

m_bUpdateRow = false;
}
Expand Down
2 changes: 2 additions & 0 deletions Source/SoundGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <queue> // // //
#include "Common.h"
#include "FamiTrackerTypes.h"
#include "ChannelState.h" // // //

#include <atomic>
#include <cstdint>
Expand Down Expand Up @@ -321,6 +322,7 @@ class CSoundGen : IAudioCallback
void PlayerSkipTo(int Row);

void ApplyGlobalState(); // // //
void ApplyGlobalTempoState(stFullState *pState);

public:
static const double NEW_VIBRATO_DEPTH[];
Expand Down