From 3cf4bc488ef3b6a36540cf64841f5e9b40d85131 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Tue, 1 Sep 2026 17:26:05 +1000 Subject: [PATCH 1/3] Add HOP FF variant --- sources/Application/Player/Player.cpp | 47 ++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/sources/Application/Player/Player.cpp b/sources/Application/Player/Player.cpp index ba1fe7f7..9d913ada 100644 --- a/sources/Application/Player/Player.cpp +++ b/sources/Application/Player/Player.cpp @@ -671,6 +671,27 @@ bool Player::ProcessChannelCommand(int channel, FourCC cmd, ushort param) { } else { gr->SetGroove(channel, param); } + } break; + case I_CMD_HOP: { + bool channel_stop = param & 0xFF == 0xFF; + if (channel_stop) { + // Stop current channel + mixer_->StopChannel(channel); + + // If all channels are stopped, stop the song if in song mode. + if(GetSequencerMode() == SM_SONG) { + bool all_channels_stopped = true; + for (int c = 0; c < SONG_CHANNEL_COUNT; c++) { + all_channels_stopped &= + !mixer_->IsChannelPlaying(c); + } + if (all_channels_stopped) { + Stop(); + } + } else { + liveQueueingMode_[channel] = QM_NONE; + } + } } break; case I_CMD_STOP: { switch (GetSequencerMode()) { @@ -882,14 +903,24 @@ void Player::playCursorPosition(int channel) { int Player::getChannelHop(int channel, int pos) { int phrase = viewData_->currentPlayPhrase_[channel]; - FourCC cc = viewData_->song_->phrase_->cmd1_[phrase * 16 + pos]; - if (cc == I_CMD_HOP) { - return (viewData_->song_->phrase_->param1_[phrase * 16 + pos]) & 0xF; - } - cc = viewData_->song_->phrase_->cmd2_[phrase * 16 + pos]; - if (cc == I_CMD_HOP) { - return (viewData_->song_->phrase_->param2_[phrase * 16 + pos]) & 0xF; - } + + Phrase *song_phrase = viewData_->song_->phrase_; + FourCC cc[] = {song_phrase->cmd1_[phrase * 16 + pos], + song_phrase->cmd2_[phrase * 16 + pos]}; + int param[] = {song_phrase->param1_[phrase * 16 + pos], + song_phrase->param2_[phrase * 16 + pos]}; + + // First hop takes precedence. + for(int i = 0; i < 2; i++) + if (cc[i] == I_CMD_HOP) { + int arg = param[i] & 0xFF; + if (arg != 0xFF) + return arg & 0xF; + else + // 'Hop stop' deferred to command processing stage. + return -1; + } + return -1; } From be5da705d5a69ec60b5310c4d2e6e5b316ebdf70 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Tue, 1 Sep 2026 23:04:51 +1000 Subject: [PATCH 2/3] Update docs --- docs/wiki/What-is-LittlePiggyTracker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index 1a3b4fe4..cbc37348 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -507,7 +507,7 @@ ARPG 4050: loops between original pitch, +4 semitones, +0 semitones, + 5 semiton ## HOP aabb -**play position will jump to the next phrase in a chain, jumping directly at position bb in the phrase.** +**play position will jump to the next phrase in a chain, jumping directly at position bb in the phrase, unless bb = FF, in which case the channel will be stopped** - hop is instant: instrument triggers and commands on the same row will be run. - no effect on instruments From 6397b8a4eca3529f302f60e51d9d5fcea578b243 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Tue, 1 Sep 2026 23:12:52 +1000 Subject: [PATCH 3/3] Clean-up --- sources/Application/Player/Player.cpp | 35 +++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/sources/Application/Player/Player.cpp b/sources/Application/Player/Player.cpp index 9d913ada..877dc160 100644 --- a/sources/Application/Player/Player.cpp +++ b/sources/Application/Player/Player.cpp @@ -673,24 +673,23 @@ bool Player::ProcessChannelCommand(int channel, FourCC cmd, ushort param) { } } break; case I_CMD_HOP: { - bool channel_stop = param & 0xFF == 0xFF; - if (channel_stop) { - // Stop current channel - mixer_->StopChannel(channel); - - // If all channels are stopped, stop the song if in song mode. - if(GetSequencerMode() == SM_SONG) { - bool all_channels_stopped = true; - for (int c = 0; c < SONG_CHANNEL_COUNT; c++) { - all_channels_stopped &= - !mixer_->IsChannelPlaying(c); - } - if (all_channels_stopped) { - Stop(); - } - } else { - liveQueueingMode_[channel] = QM_NONE; - } + bool channel_stop = (param & 0xFF) == 0xFF; + if (channel_stop) { + // Stop current channel + mixer_->StopChannel(channel); + + // If all channels are stopped, stop the song if in song mode. + if (GetSequencerMode() == SM_SONG) { + bool all_channels_stopped = true; + for (int c = 0; c < SONG_CHANNEL_COUNT; c++) { + all_channels_stopped &= !mixer_->IsChannelPlaying(c); + } + if (all_channels_stopped) { + Stop(); + } + } else { + liveQueueingMode_[channel] = QM_NONE; + } } } break; case I_CMD_STOP: {