This repository has been archived by the owner on Oct 16, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
N163 Zxx
nyanpasu64 edited this page Jul 2, 2018
·
6 revisions
The order CChannelHandler::HandleNoteData processes events on the same row (https://github.com/nyanpasu64/j0CC-FamiTracker/wiki/Effects):
- Effect:
CChannelHandler::HandleEffect(name, param)
- Note:
CChannelHandler::HandleEmptyNote()
,HandleCut()
,HandleRelease()
,HandleNote(note, octave)
- Instrument:
CChannelHandler::HandleInstrument(isTrigger, isNewInstr)
What order should events be processed?
- 3xx on note row: effect before note
- DPCM pitch: note before instr
-
N163 Zxx bounds checking: instr before effect(not satisfied, causing Zxx to bounds-check based on the instrument used 1 row above)- I have removed this dependency by removing Zxx bounds checking.
hooray, circular dependencies.
I may move Zxx into a new "handle effect after instrument" method, also handling 1xx and 2xx. I ended up removing Zxx bounds checking.
Test Case: n163-zxx-validation.zip
void CSeqInstHandlerN163::LoadInstrument(std::shared_ptr<CInstrument> pInst) {
pInterface->SetWaveLength(pN163Inst->GetWaveSize());
pInterface->SetWavePosition(pN163Inst->GetWavePos());
pInterface->SetWaveCount(pN163Inst->GetWaveCount());
RequestWaveUpdate();
}
void CChannelHandlerN163::SetWaveLength(int Length) {
m_iWaveLen = Length;
}
bool CChannelHandlerN163::HandleEffect(effect_t EffNum, unsigned char EffParam) {
switch (EffNum) {
case EF_N163_WAVE_BUFFER:
if (EffParam == 0x7F) {
m_iWavePos = m_iWavePosOld;
m_bDisableLoad = false;
} else {
if (EffParam + (m_iWaveLen >> 1) > 0x80 - 8 * m_iChannels) break;
m_iWavePos = EffParam << 1;
m_bDisableLoad = true;
}
if (auto pHandler = dynamic_cast<CSeqInstHandlerN163*>(m_pInstHandler.get()))
pHandler->RequestWaveUpdate();
break;
}
return true;
}
HertzDevil release build :(
CSoundDriver::Tick() Line 166
CSoundDriver::UpdateChannels() Line 234
CSoundDriver::ForeachTrack(CSoundDriver::UpdateChannels::__l2::void <lambda>(CChannelHandler &, CTrackerChannel &, stChannelID) f) Line 98
CSoundDriver::UpdateChannels::__l2::<lambda>(CChannelHandler & Chan, CTrackerChannel & TrackerChan, stChannelID ID) Line 247
CChannelHandler::PlayNote(stChanNote NoteData) Line 278
CChannelHandler::HandleNoteData(stChanNote & NoteData) Line 365
CChannelHandlerN163::HandleEffect(effect_t EffNum, unsigned char EffParam) Line 89
CChannelHandler::HandleNoteData(stChanNote & NoteData) Line 422
CChannelHandlerN163::HandleInstrument(bool Trigger, bool NewInstrument) Line 104
CChannelHandler::HandleInstrument(bool Trigger, bool NewInstrument) Line 444
CSeqInstHandlerN163::LoadInstrument(std::shared_ptr<CInstrument> pInst) Line 46
HertzDevil da6767c:
CSoundGen::BeginPlayer(std::unique_ptr<CPlayerCursor,std::default_delete<CPlayerCursor> > Pos) Line 610
CSoundGen::ApplyGlobalState() Line 624
CSoundDriver::LoadSoundState(const CSongState & state) Line 200
CSoundDriver::ForeachTrack<void <lambda>(CChannelHandler &, CTrackerChannel &, chan_id_t) >(CSoundDriver::LoadSoundState::__l2::void <lambda>(CChannelHandler &, CTrackerChannel &, chan_id_t) f) Line 111
CSoundDriver::LoadSoundState::__l2::<lambda>(CChannelHandler & ch, CTrackerChannel & tr, chan_id_t id) Line 198
CChannelHandler::ApplyChannelState(const stChannelState & State) Line 209
CChannelHandlerN163::HandleInstrument(bool Trigger, bool NewInstrument) Line 100
CChannelHandler::HandleInstrument(bool Trigger, bool NewInstrument) Line 448
CSeqInstHandlerN163::LoadInstrument(std::shared_ptr<CInstrument> pInst) Line 46
CChannelHandler::ApplyChannelState(const stChannelState & State) Line 214
CChannelHandlerN163::HandleEffect(effect_t EffNum, unsigned char EffParam) Line 85
CSoundDriver::Tick() Line 211
CSoundDriver::UpdateChannels() Line 298
CSoundDriver::ForeachTrack<void <lambda>(CChannelHandler &, CTrackerChannel &, chan_id_t) >(CSoundDriver::UpdateChannels::__l2::void <lambda>(CChannelHandler &, CTrackerChannel &, chan_id_t) f) Line 111
CSoundDriver::UpdateChannels::__l2::<lambda>(CChannelHandler & Chan, CTrackerChannel & TrackerChan, chan_id_t ID) Line 288
CChannelHandler::PlayNote(stChanNote NoteData) Line 281
CChannelHandler::HandleNoteData(stChanNote & NoteData) Line 366
CChannelHandlerN163::HandleEffect(effect_t EffNum, unsigned char EffParam) Line 85
The first 2 calls do not occur on N163 Zxx Validation (Row 4).0cc
and the bug reappears.
- (checks if note exists, pushes to echo buffer)
- HandleEffect
- Write volume
- (calculates instrument #)
- m_iNote = RunNote(...)
- HandleInstrument.
switch (pNoteData->Note) { // // // set note value before loading instrument
case NONE: case HALT: case RELEASE: break;
default: m_iNote = RunNote(pNoteData->Octave, pNoteData->Note);
}
CChannelHandler::HandleInstrument calls CDPCMChan::HandleNoteData and CChannelHandler::HandleInstrument.
- CDPCMChan::HandleNoteData
- m_iCustomPitch = -1;
- CChannelHandler::HandleInstrument calls CDPCMChan::PlaySample
- m_iPeriod = m_iCustomPitch != -1 ? m_iCustomPitch : Pitch;
So notes must be handled before instruments.
SetupSlide() touches m_iNote:
- Effect 3xx begins before current note!
- CChannelHandler::HandleEffect with EF_PORTAMENTO:
- SetupSlide() depends on m_iNote.
- HandleNoteData() assigns m_iNote after HandleEffect()
- m_iNote = RunNote(pNoteData->Octave, pNoteData->Note);
- EF_SLIDE_DOWN and EF_SLIDE_UP
- SetupSlide() is called specifically after m_iNote is assigned.
- GetNote()
- CInstHandlerDPCM
- TriggerInstrument(): void
- CSeqInstHandler
- ProcessSequence(int, unsigned, int): bool
- UpdateInstrument(): void
- CInstHandlerDPCM
- CChannelHandler
- CChannelHandler(int, int)
- (57,2) m_iNote(0),
- GetNote() const: int
- (981,9) return m_iNote;
- GetPitch() const: int
- (106,23) if (m_iPitch != 0 && m_iNote != 0 && m_pNoteLookupTable != NULL) {
- (108,27) int LowNote = std::max(m_iNote - PITCH_WHEEL_RANGE, 0);
- (109,27) int HighNote = std::min(m_iNote + PITCH_WHEEL_RANGE, 95);
- (110,34) int Freq = m_pNoteLookupTable[m_iNote];
- HandleNoteData(stChanNote*, int): void
- (402,11) default: m_iNote = RunNote(pNoteData->Octave, pNoteData->Note);
- ResetChannel(): void
- (149,2) m_iNote = 0; // // //
- SetNote(int): void
- (976,2) m_iNote = Note;
- SetupSlide(): void
- (546,29) m_iPortaTo = TriggerNote(m_iNote);
- (549,3) m_iNote = m_iNote + (m_iEffectParam & 0xF);
- (549,13) m_iNote = m_iNote + (m_iEffectParam & 0xF);
- (551,28) m_iPortaTo = TriggerNote(m_iNote);
- (554,3) m_iNote = m_iNote - (m_iEffectParam & 0xF);
- (554,13) m_iNote = m_iNote - (m_iEffectParam & 0xF);
- (556,28) m_iPortaTo = TriggerNote(m_iNote);
- UpdateEffects(): void
- (765,29) SetPeriod(TriggerNote(m_iNote));
- (768,29) SetPeriod(TriggerNote(m_iNote + (m_iEffectParam >> 4)));
- (773,29) SetPeriod(TriggerNote(m_iNote + (m_iEffectParam & 0x0F)));
- UpdateTranspose(): void
- (705,11) SetNote(m_iNote + m_iTransposeTarget * (m_bTransposeDown ? -1 : 1));
- (706,25) SetPeriod(TriggerNote(m_iNote));
- CChannelHandler(int, int)
- CChannelHandlerN163
- HandleCut(): void
- (120,2) m_iNote = 0;
- HandleCut(): void
- CChannelHandlerS5B
- HandleCut(): void
- (151,2) m_iNote = 0;
- HandleCut(): void
- CDPCMChan
- HandleNote(int, int): void
- (622,2) m_iNote = MIDI_NOTE(Octave, Note); // // //
- (623,14) TriggerNote(m_iNote);
- HandleNote(int, int): void
- CNoiseChan
- HandleNote(int, int): void
- (393,2) m_iNote = NewNote;
- SetupSlide(): void
- (405,3) m_iNote += (m_iEffectParam & 0xF);
- (409,3) m_iNote -= (m_iEffectParam & 0xF);
- (416,19) RegisterKeyState(m_iNote);
- (417,15) m_iPortaTo = m_iNote;
- HandleNote(int, int): void
- CVRC7Channel
- ClearRegisters(): void
- (329,2) m_iNote = 0;
- ClearRegisters(): void