From 523345221e2221ff79b1bef46e498dde842438ee Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Mon, 16 Feb 2026 23:20:56 +0000 Subject: [PATCH 1/7] Sample cursor --- arm9/source/main.cpp | 52 +++++++- arm9/source/tobkit/sampledisplay.cpp | 188 +++++++++++++++++++++++---- arm9/source/tobkit/sampledisplay.h | 21 ++- tobkit/include/tobkit/gui.h | 7 + tobkit/source/gui.cpp | 18 +++ 5 files changed, 251 insertions(+), 35 deletions(-) diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index 5dd3d37..23d058f 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -450,7 +450,7 @@ void onKeypress(u8 note) void onKeyrelease(void) { - // stop cursor + sampledisplay->requestRedraw(); } void handleNoteStroke(u8 note) @@ -645,7 +645,7 @@ void handleSampleChange(const u16 newsample) return; } - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, newsample, lbinstruments->getidx()); sampledisplay->hideLoopPoints(); nssamplevolume->setValue( (smp->getVolume()+1)/4 ); nspanning->setValue(smp->getPanning()/2); @@ -748,6 +748,19 @@ void updateTempoAndBpm(void) nbtempo->setValue(song->getTempo()); } +void cursorTimerHandler(void) +{ + sampledisplay->calcCursor(); +} + +void startCursorTimer(void) +{ + TIMER1_DATA = TIMER_FREQ_64(60); // Call handler every frame + TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_DIV_64; + irqSet(IRQ_TIMER1, cursorTimerHandler); + irqEnable(IRQ_TIMER1); +} + void setSong(Song *newsong) { song = newsong; @@ -816,7 +829,7 @@ void setSong(Song *newsong) inst = song->getInstrument(state->instrument); if(inst != NULL) { - sampledisplay->setSample(inst->getSample(state->sample)); + sampledisplay->setSample(inst->getSample(state->sample), state->sample, state->instrument); } strncpy(str, song->getName(), sizeof(str)-1); @@ -1392,6 +1405,7 @@ void stopPlay(void) stop(); + sampledisplay->requestRedraw(); buttonpause->hide(); buttonplay->show(); } @@ -1403,6 +1417,7 @@ void pausePlay(void) // Send stop command CommandStopPlay(); + sampledisplay->requestRedraw(); buttonpause->hide(); buttonplay->show(); } @@ -2963,7 +2978,7 @@ void sample_del_selection(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -2985,7 +3000,7 @@ void sample_fade_in(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -3007,7 +3022,7 @@ void sample_fade_out(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -3032,7 +3047,7 @@ void sample_reverse(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -3367,6 +3382,19 @@ void sampleDrawToggle(bool on) sampledisplay->setDrawMode(on); } +void handleOverlayWidgetChange(u8 screen, bool visible) +{ + if (screen == SUB_SCREEN) + { + if (sampledisplay != NULL && sampledisplay->is_visible()) + { + if (visible) sampledisplay->hideCursor(); + else sampledisplay->showCursor(); + sampledisplay->pleaseDraw(); + } + } +} + #define RIGHT_SIDE_BUTTON_WIDTH 30 #define RIGHT_SIDE_BUTTON_X 225 @@ -3374,6 +3402,7 @@ void setupGUI(bool dldi_enabled) { gui = new GUI(); gui->setTheme(settings->getTheme(), settings->getTheme()->col_bg); + gui->setOnOverlayChanged(handleOverlayWidgetChange); kb = new Piano(0, 152, 224, 40, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram); kb->set_overdraw(false); @@ -4220,6 +4249,9 @@ void VblankHandler(void) u16 keysup = keysUp(); u16 keysheld = keysHeld(); touchRead(&touch); + + if (sampledisplay != NULL && !gui->hasOverlayWidget(SUB_SCREEN)) + sampledisplay->pleaseDraw(); if(keysdown & KEY_TOUCH) @@ -4530,6 +4562,12 @@ int main(int argc, char **argv) { CommandSetSong(song); setupGUI(fat_success); + + startCursorTimer(); + SampleCursor *scursors = (SampleCursor*)ntxm_ccalloc(MAX_CHANNELS, sizeof(SampleCursor)); + CommandSetCursorPosPtr(scursors); + sampledisplay->setCursorPosPtr((SampleCursor*)memUncached(scursors)); + action_buffer->register_change_callback({&actionBufferChangeCallback}); applySettings(); diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index 579a368..75a7e7c 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -37,13 +37,13 @@ using namespace tobkit; // Constructor sets base variables SampleDisplay::SampleDisplay(u8 _x, u8 _y, u8 _width, u8 _height, u16 **_vram, Sample *_smp) :Widget(_x, _y, _width, _height, _vram), - smp(_smp), + smp(_smp), smpidx(0), instidx(0), selstart(0), selend(0), selection_exists(false), pen_is_down(false), active(false), loop_points_visible(false), pen_on_loop_start_point(false), pen_on_loop_end_point(false), pen_on_zoom_in(false), pen_on_zoom_out(false), pen_on_scroll_left(false), pen_on_scroll_right(false), pen_on_scrollthingy(false), pen_on_scrollbar(false), scrollthingypos(0), scrollthingywidth(width-2*SCROLLBUTTON_HEIGHT+2), pen_x_on_scrollthingy(0), zoom_level(0), scrollpos(0), - snap_to_zero_crossings(true), draw_mode(false) + snap_to_zero_crossings(true), draw_mode(false), cursor_draw_mode(true), do_redraw(true) { } @@ -113,7 +113,7 @@ void SampleDisplay::penDown(u8 px, u8 py) else if(active) { selstart = selend = pixelToSample(px - x); selection_exists = false; - draw(); + requestRedraw(); } } } @@ -129,14 +129,14 @@ void SampleDisplay::penUp(u8 px, u8 py) if( pen_on_zoom_in || pen_on_zoom_out || pen_on_scroll_left || pen_on_scroll_right || pen_on_scrollthingy || pen_on_scrollbar) { pen_on_zoom_in = pen_on_zoom_out = pen_on_scroll_left = pen_on_scroll_right = pen_on_scrollthingy = pen_on_scrollbar = false; - draw(); + requestRedraw(); } else if(pen_on_loop_start_point) { if(snap_to_zero_crossings) { s32 oldstart = smp->getLoopStart(); s32 zerocrossing = find_zero_crossing_near(smp->getLoopStart()); if(zerocrossing != -1) { smp->setLoopStartAndLength(zerocrossing, smp->getLoopLength() - (zerocrossing - oldstart)); - draw(); + requestRedraw(); } } } else if(pen_on_loop_end_point) { @@ -150,7 +150,7 @@ void SampleDisplay::penUp(u8 px, u8 py) newlength = 0; } smp->setLoopStartAndLength(newstart, newlength); - draw(); + requestRedraw(); } } } @@ -223,18 +223,117 @@ void SampleDisplay::penMove(u8 px, u8 py) } } - draw(); + requestRedraw(); } -void SampleDisplay::setSample(Sample *_smp) +void SampleDisplay::setCursorPosPtr(SampleCursor *cursorpos_) { - smp = _smp; + cursorpos = cursorpos_; +} + +void tobkit::SampleDisplay::hideCursor(void) +{ + cursor_draw_mode = false; + requestRedraw(); +} + +void tobkit::SampleDisplay::showCursor(void) +{ + cursor_draw_mode = true; + requestRedraw(); +} + +void SampleDisplay::calcCursor() +{ + if (smp == 0) return; + for (int chn = 0; chn < 16; ++chn) + { + if (cursorpos[chn].instidx == 255 || !(cursorpos[chn].active)) continue; + + SampleCursor *playingNote = &cursorpos[chn]; + + const u8 looptype = smp->getLoop(); + + const u64 loopstart = (u64)(smp->getLoopStart()) << 32; + const u64 looplen = (u64)(smp->getLoopLength()) << 32; + const u64 nsamps = (u64)(smp->getNSamples()) << 32; + const u64 loopend = loopstart + looplen; + + u8& looprev = playingNote->looprev; + u64& playpos = playingNote->playbackpos; + + const u64 step = (((u64)(smp->getPlaybackFreq(playingNote->note)) /* * (u64)n_ticks */) << 32) / 60; // timer + + // are we going backwards? + if (looprev) { + // calculate position if we are "bouncing" from the start + if (step > playpos) { + playpos = loopstart + step - playpos; + looprev = false; + } + else + playpos -= step; + } + else + playpos += step; + + // if between frames the cursor jumped past the end of the sample put it in the correct position after the start + if (looptype == FORWARD_LOOP && playpos >= loopend) + playpos = loopstart + playpos - loopend; + + else if (looptype == PING_PONG_LOOP) { + // If we're going backwards but we jumped beyond the first loop handle, + // calculate where we should be. (loopstart + (loopstart - playpos)), where (loopstart - playpos) is the error + if (looprev && playpos <= loopstart) { + playpos = 2 * loopstart - playpos; + looprev = false; + } + else if (!looprev && playpos >= loopend) { + playpos = 2 * loopend - playpos; + looprev = true; + } + } + + if (looptype == NO_LOOP && playpos >= nsamps) { + requestRedraw(); + continue; + } + + if (looptype != NO_LOOP && looplen <= step && playpos > loopstart) + if (looptype == PING_PONG_LOOP && looprev) + playpos = loopend - (step % looplen); + else + playpos = loopstart + (step % looplen); + + if (looptype == NO_LOOP && playpos >= nsamps) + playpos = 0; + + u16 draw_cursor_at = sampleToPixel(playpos >> 32); + + if (draw_cursor_at < width) + cursors_xpos[chn] = draw_cursor_at; + + requestRedraw(); + } + +} + + +void SampleDisplay::setSample(Sample *_smp, u8 _smpidx, u8 _instidx) +{ + smpidx = _smpidx; + instidx = _instidx; + selection_exists = false; selstart = selend = 0; if(_smp == 0) { loop_points_visible = false; } - draw(); + + if (_smp != smp || instidx != _instidx) + requestRedraw(); + + smp = _smp; } void SampleDisplay::select_all(void) @@ -244,7 +343,7 @@ void SampleDisplay::select_all(void) selection_exists = true; selstart = 0; selend = smp->getNSamples(); - draw(); + requestRedraw(); } void SampleDisplay::clear_selection(void) @@ -254,7 +353,7 @@ void SampleDisplay::clear_selection(void) selection_exists = false; selstart = 0; selend = 0; - draw(); + requestRedraw(); } bool SampleDisplay::getSelection(u32 *startsample, u32 *endsample) @@ -277,7 +376,7 @@ void SampleDisplay::pleaseDraw(void) void SampleDisplay::setActive(void) { active = true; - draw(); + requestRedraw(); } void SampleDisplay::setInactive(void) @@ -285,20 +384,20 @@ void SampleDisplay::setInactive(void) active = false; selection_exists = false; selstart = selend = 0; - draw(); + requestRedraw(); } void SampleDisplay::setDrawMode(bool _on) { draw_mode = _on; - draw(); + requestRedraw(); } void SampleDisplay::showLoopPoints(void) { if(loop_points_visible == false) { loop_points_visible = true; - draw(); + requestRedraw(); } } @@ -307,7 +406,7 @@ void SampleDisplay::hideLoopPoints(void) if(loop_points_visible == true) { loop_points_visible = false; - draw(); + requestRedraw(); } } @@ -316,6 +415,17 @@ void SampleDisplay::setSnapToZeroCrossing(bool snap) snap_to_zero_crossings = snap; } +void SampleDisplay::requestRedraw(void) +{ + do_redraw = true; +} + +void SampleDisplay::reveal(void) +{ + requestRedraw(); + Widget::reveal(); +} + /* ===================== PRIVATE ===================== */ long SampleDisplay::find_zero_crossing_near(long pos) @@ -386,9 +496,11 @@ long SampleDisplay::find_zero_crossing_near(long pos) void SampleDisplay::draw(void) { - if(!isExposed()) + if(!isExposed() || !do_redraw) return; + do_redraw = false; + // Border if(active==false) { drawBorder(theme->col_outline); @@ -501,9 +613,24 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); - u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; - u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; + u16 colortable_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform); + u16 bg_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg); + data = &(base[f32toint(pos)]); s32 maxsmp = -32767, minsmp = 32767; @@ -547,9 +674,24 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); - u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; - u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; + u16 colortable_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform); + u16 bg_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg); + data = &(base[f32toint(pos)]); s8 maxsmp = -127, minsmp = 127; @@ -725,7 +867,7 @@ void SampleDisplay::scroll(u32 newscrollpos) scrollthingypos = scrollpos * scroll_width / (disp_width - window_width); calcScrollThingy(); - draw(); + requestRedraw(); } // Calculate height and position of the scroll thingy diff --git a/arm9/source/tobkit/sampledisplay.h b/arm9/source/tobkit/sampledisplay.h index c201b5a..546d697 100644 --- a/arm9/source/tobkit/sampledisplay.h +++ b/arm9/source/tobkit/sampledisplay.h @@ -40,7 +40,7 @@ namespace tobkit { #define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed #define MIN_SCROLLTHINGY_WIDTH 15 -#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-2) // height of the visible window +#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-3) // height of the visible window class SampleDisplay: public Widget { public: @@ -55,12 +55,18 @@ class SampleDisplay: public Widget { // Drawing request void pleaseDraw(void); - - void setSample(Sample *_smp); - + void requestRedraw(void); + void reveal(void); + + void setSample(Sample *_smp, u8 smpidx=0, u8 instidx=255); void select_all(void); void clear_selection(void); + void calcCursor(); + void setCursorPosPtr(SampleCursor *cursorpos); + void hideCursor(void); + void showCursor(void); + // Return start and end sample of selection bool getSelection(u32 *startsample, u32 *endsample); @@ -88,7 +94,7 @@ class SampleDisplay: public Widget { s32 sampleToPixel(u32 sample); Sample *smp; - + u8 smpidx, instidx; u32 selstart, selend; bool selection_exists; @@ -116,8 +122,13 @@ class SampleDisplay: public Widget { bool snap_to_zero_crossings; bool draw_mode; + bool cursor_draw_mode; + bool do_redraw; u8 draw_last_x, draw_last_y; + + SampleCursor *cursorpos; + u32 cursors_xpos[16] = {0}; }; }; diff --git a/tobkit/include/tobkit/gui.h b/tobkit/include/tobkit/gui.h index 5c6ec9d..3b7d88c 100644 --- a/tobkit/include/tobkit/gui.h +++ b/tobkit/include/tobkit/gui.h @@ -57,6 +57,12 @@ class GUI { // Remove the overlay widget void unregisterOverlayWidget(u8 screen = SUB_SCREEN); + // Is there an overlay widget? + bool hasOverlayWidget(u8 screen = SUB_SCREEN); + + // Event handler for when an overlay widget is about to draw. (so we can clean up widgets underneath) + void setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)); + // Event calls void penDown(u8 x, u8 y); void penUp(u8 x, u8 y); // Remove the coordinates here! @@ -90,6 +96,7 @@ class GUI { Widget *activeWidget; u8 activeScreen; Widget *overlayWidgetMain, *overlayWidgetSub; + void (*onOverlayChanged)(u8, bool); u16 overlayShortcuts; Theme *theme; u16 bgcolor; diff --git a/tobkit/source/gui.cpp b/tobkit/source/gui.cpp index d8f153e..8426312 100644 --- a/tobkit/source/gui.cpp +++ b/tobkit/source/gui.cpp @@ -30,6 +30,7 @@ GUI::GUI() for(i=0;i<14;++i) { shortcuts.push_back(0); } + onOverlayChanged = 0; } // Sets the theme - mandatory! @@ -103,8 +104,10 @@ void GUI::unregisterWidget(Widget *w) void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) { if(screen == SUB_SCREEN) { + onOverlayChanged(SUB_SCREEN, true); overlayWidgetSub = w; } else { + onOverlayChanged(MAIN_SCREEN, true); overlayWidgetMain = w; } overlayShortcuts = listeningButtons; @@ -116,11 +119,13 @@ void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) void GUI::unregisterOverlayWidget(u8 screen) { if(screen == SUB_SCREEN) { + onOverlayChanged(SUB_SCREEN, false); if(activeWidget==overlayWidgetSub) { activeWidget = 0; } overlayWidgetSub = 0; } else { + onOverlayChanged(MAIN_SCREEN, false); if(activeWidget==overlayWidgetMain) { activeWidget = 0; } @@ -129,6 +134,19 @@ void GUI::unregisterOverlayWidget(u8 screen) overlayShortcuts = 0; } +bool GUI::hasOverlayWidget(u8 screen) +{ + if (screen == SUB_SCREEN) + return overlayWidgetSub != NULL; + else + return overlayWidgetMain != NULL; +} + +void GUI::setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)) +{ + onOverlayChanged = _onOverlayChanged; +} + // Event calls void GUI::penDown(u8 x, u8 y) { From 7d5c74556716bf2d283bcf1b52cdeecc82689895 Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Wed, 18 Feb 2026 08:47:33 +0000 Subject: [PATCH 2/7] draw fix --- arm9/source/main.cpp | 3 ++- arm9/source/tobkit/sampledisplay.cpp | 2 +- arm9/source/tobkit/sampledisplay.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index 23d058f..e328855 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -657,7 +657,8 @@ void handleSampleChange(const u16 newsample) else rbg_sampleloop->setActive(0); - updateKeyLabels(); + if (fxkb->is_visible()) updateKeyLabels(); + if (!had_changes) setHasUnsavedChanges(false); /* printf("Selected:"); diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index 75a7e7c..a0ebc22 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -262,7 +262,7 @@ void SampleDisplay::calcCursor() u8& looprev = playingNote->looprev; u64& playpos = playingNote->playbackpos; - const u64 step = (((u64)(smp->getPlaybackFreq(playingNote->note)) /* * (u64)n_ticks */) << 32) / 60; // timer + const u64 step = (((u64)(playingNote->playbackfreq) /* * (u64)n_ticks */) << 32) / 60; // timer // are we going backwards? if (looprev) { diff --git a/arm9/source/tobkit/sampledisplay.h b/arm9/source/tobkit/sampledisplay.h index 546d697..0d32405 100644 --- a/arm9/source/tobkit/sampledisplay.h +++ b/arm9/source/tobkit/sampledisplay.h @@ -40,7 +40,7 @@ namespace tobkit { #define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed #define MIN_SCROLLTHINGY_WIDTH 15 -#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-3) // height of the visible window +#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-2) // height of the visible window class SampleDisplay: public Widget { public: From 195a067077f890610dbd57ab2c77c4cbda09fa8c Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Tue, 24 Feb 2026 19:59:15 +0000 Subject: [PATCH 3/7] Wip sprite stuff --- arm9/source/main.cpp | 85 +++++++++------- arm9/source/tobkit/sampledisplay.cpp | 142 +++++++++++---------------- arm9/source/tobkit/sampledisplay.h | 12 +-- tobkit/include/tobkit/gui.h | 4 - tobkit/include/tobkit/theme.h | 3 +- tobkit/source/gui.cpp | 10 -- tobkit/source/theme.cpp | 5 +- 7 files changed, 116 insertions(+), 145 deletions(-) diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index e328855..eb4b341 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -450,7 +450,6 @@ void onKeypress(u8 note) void onKeyrelease(void) { - sampledisplay->requestRedraw(); } void handleNoteStroke(u8 note) @@ -660,21 +659,13 @@ void handleSampleChange(const u16 newsample) if (fxkb->is_visible()) updateKeyLabels(); if (!had_changes) setHasUnsavedChanges(false); - /* - printf("Selected:"); - if(smp->is16bit()) { - printf("16bit "); - } else { - printf("8bit "); - } - if(smp->getLoop() != 0) { - printf("looping "); - } - printf("Sample.\n"); - printf("length: %u\n", smp->getNSamples()); - */ } +void handleCursorUpdate(u8 chn, u8 x, bool shouldHide) +{ + bool hide = shouldHide || gui->hasOverlayWidget(SUB_SCREEN); + oamSub.oamMemory[chn].x = hide ? 199 : x-3; // can't hide sprites if we scale them, so let's just draw them offscreen +} void volEnvSetInst(Instrument *inst) { @@ -762,6 +753,8 @@ void startCursorTimer(void) irqEnable(IRQ_TIMER1); } + + void setSong(Song *newsong) { song = newsong; @@ -1406,7 +1399,6 @@ void stopPlay(void) stop(); - sampledisplay->requestRedraw(); buttonpause->hide(); buttonplay->show(); } @@ -1418,7 +1410,6 @@ void pausePlay(void) // Send stop command CommandStopPlay(); - sampledisplay->requestRedraw(); buttonpause->hide(); buttonplay->show(); } @@ -2190,6 +2181,9 @@ void reloadSkin(void) u32 colcol = col | col << 16; dmaFillWords(colcol, sub_vram + (256 * y) + 224, (256 - 224) * 2); } + + *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + gui->draw(); redrawSubScreen(); setRecordMode(state->recording); @@ -3383,19 +3377,6 @@ void sampleDrawToggle(bool on) sampledisplay->setDrawMode(on); } -void handleOverlayWidgetChange(u8 screen, bool visible) -{ - if (screen == SUB_SCREEN) - { - if (sampledisplay != NULL && sampledisplay->is_visible()) - { - if (visible) sampledisplay->hideCursor(); - else sampledisplay->showCursor(); - sampledisplay->pleaseDraw(); - } - } -} - #define RIGHT_SIDE_BUTTON_WIDTH 30 #define RIGHT_SIDE_BUTTON_X 225 @@ -3403,7 +3384,6 @@ void setupGUI(bool dldi_enabled) { gui = new GUI(); gui->setTheme(settings->getTheme(), settings->getTheme()->col_bg); - gui->setOnOverlayChanged(handleOverlayWidgetChange); kb = new Piano(0, 152, 224, 40, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram); kb->set_overdraw(false); @@ -3413,6 +3393,7 @@ void setupGUI(bool dldi_enabled) fxkb = new FXKeyboard(0, 152, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram, onFxKeyPressed, false); fxkb->set_overdraw(false); + *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; pixmaplogo = new GradientIcon(98, 1, 80, 17, (const u32*) nitrotracker_logo_raw, &sub_vram); @@ -4250,10 +4231,8 @@ void VblankHandler(void) u16 keysup = keysUp(); u16 keysheld = keysHeld(); touchRead(&touch); - - if (sampledisplay != NULL && !gui->hasOverlayWidget(SUB_SCREEN)) - sampledisplay->pleaseDraw(); + oamUpdate(&oamSub); if(keysdown & KEY_TOUCH) { @@ -4461,10 +4440,11 @@ int main(int argc, char **argv) { videoSetMode(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG2_ACTIVE); // Sub screen: Keyboard tiles, Typewriter tiles and ERB - videoSetModeSub(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE); + videoSetModeSub(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D); vramSetPrimaryBanks(VRAM_A_MAIN_BG_0x06000000, VRAM_B_MAIN_BG_0x06020000, - VRAM_C_SUB_BG_0x06200000 , VRAM_D_LCD); + VRAM_C_SUB_BG_0x06200000 , VRAM_D_SUB_SPRITE); + // SUB_BG0 for Piano Tiles videoBgEnableSub(0); @@ -4493,6 +4473,34 @@ int main(int argc, char **argv) { int sub_bg = bgInitSub(2, BgType_Bmp16, BgSize_B16_256x256, 2, 0); bgSetPriority(sub_bg, 0); + oamInit(&oamSub, SpriteMapping_1D_32, false); + + windowEnableSub(WINDOW_0); + + bgWindowEnable(sub_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); + bgWindowEnable(piano_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); + bgWindowEnable(typewriter_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); + + windowSetBoundsSub(WINDOW_0, 4, 24, 4+128, 23+61); // sampledisplay x1,y1,x2,y2 + oamWindowEnable(&oamSub, WINDOW_0); + + u16 *gfxSub = oamAllocateGfx(&oamSub, SpriteSize_16x32, SpriteColorFormat_16Color); + + *(gfxSub+64)=1; + // *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + oamSub.oamRotationMemory[0].vdy = 0; // max y scale + + for (int c=0;c<16;++c) + { + oamSet(&oamSub, c, 256, 23, 0, 0, + SpriteSize_16x32, + SpriteColorFormat_16Color, + gfxSub, + 0, true, false, false, false, false); + } + + //for (int i=0;i<16;++i) oamSetHidden(&oamSub, i, true); // using hide=true in oamSet makes the draw broken fsr + // Special effects #ifdef DEBUG REG_BLDCNT = BLEND_ALPHA | BLEND_SRC_BG0 | BLEND_DST_BG2; @@ -4563,15 +4571,18 @@ int main(int argc, char **argv) { CommandSetSong(song); setupGUI(fat_success); - + startCursorTimer(); SampleCursor *scursors = (SampleCursor*)ntxm_ccalloc(MAX_CHANNELS, sizeof(SampleCursor)); CommandSetCursorPosPtr(scursors); sampledisplay->setCursorPosPtr((SampleCursor*)memUncached(scursors)); - + sampledisplay->setOnCursorUpdate(handleCursorUpdate); + action_buffer->register_change_callback({&actionBufferChangeCallback}); applySettings(); + + *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; setSong(song); #ifndef DEBUG diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index a0ebc22..146e08d 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -37,13 +37,13 @@ using namespace tobkit; // Constructor sets base variables SampleDisplay::SampleDisplay(u8 _x, u8 _y, u8 _width, u8 _height, u16 **_vram, Sample *_smp) :Widget(_x, _y, _width, _height, _vram), - smp(_smp), smpidx(0), instidx(0), + smp(_smp), selstart(0), selend(0), selection_exists(false), pen_is_down(false), active(false), loop_points_visible(false), pen_on_loop_start_point(false), pen_on_loop_end_point(false), pen_on_zoom_in(false), pen_on_zoom_out(false), pen_on_scroll_left(false), pen_on_scroll_right(false), pen_on_scrollthingy(false), pen_on_scrollbar(false), scrollthingypos(0), scrollthingywidth(width-2*SCROLLBUTTON_HEIGHT+2), pen_x_on_scrollthingy(0), zoom_level(0), scrollpos(0), - snap_to_zero_crossings(true), draw_mode(false), cursor_draw_mode(true), do_redraw(true) + snap_to_zero_crossings(true), draw_mode(false) { } @@ -53,6 +53,11 @@ SampleDisplay::~SampleDisplay(void) } +void SampleDisplay::setOnCursorUpdate(void(*_onCursorUpdate)(u8, u8, bool)) +{ + onCursorUpdate = _onCursorUpdate; +} + void SampleDisplay::penDown(u8 px, u8 py) { if( (smp==0) || ( (active==false) && (loop_points_visible==false) && (draw_mode == false) ) ) @@ -113,7 +118,7 @@ void SampleDisplay::penDown(u8 px, u8 py) else if(active) { selstart = selend = pixelToSample(px - x); selection_exists = false; - requestRedraw(); + draw(); } } } @@ -129,14 +134,14 @@ void SampleDisplay::penUp(u8 px, u8 py) if( pen_on_zoom_in || pen_on_zoom_out || pen_on_scroll_left || pen_on_scroll_right || pen_on_scrollthingy || pen_on_scrollbar) { pen_on_zoom_in = pen_on_zoom_out = pen_on_scroll_left = pen_on_scroll_right = pen_on_scrollthingy = pen_on_scrollbar = false; - requestRedraw(); + draw(); } else if(pen_on_loop_start_point) { if(snap_to_zero_crossings) { s32 oldstart = smp->getLoopStart(); s32 zerocrossing = find_zero_crossing_near(smp->getLoopStart()); if(zerocrossing != -1) { smp->setLoopStartAndLength(zerocrossing, smp->getLoopLength() - (zerocrossing - oldstart)); - requestRedraw(); + draw(); } } } else if(pen_on_loop_end_point) { @@ -150,7 +155,7 @@ void SampleDisplay::penUp(u8 px, u8 py) newlength = 0; } smp->setLoopStartAndLength(newstart, newlength); - requestRedraw(); + draw(); } } } @@ -223,7 +228,7 @@ void SampleDisplay::penMove(u8 px, u8 py) } } - requestRedraw(); + draw(); } void SampleDisplay::setCursorPosPtr(SampleCursor *cursorpos_) @@ -231,24 +236,18 @@ void SampleDisplay::setCursorPosPtr(SampleCursor *cursorpos_) cursorpos = cursorpos_; } -void tobkit::SampleDisplay::hideCursor(void) -{ - cursor_draw_mode = false; - requestRedraw(); -} - -void tobkit::SampleDisplay::showCursor(void) -{ - cursor_draw_mode = true; - requestRedraw(); -} - void SampleDisplay::calcCursor() { if (smp == 0) return; for (int chn = 0; chn < 16; ++chn) { - if (cursorpos[chn].instidx == 255 || !(cursorpos[chn].active)) continue; + bool drawCursor = false; + + if (cursorpos[chn].instidx == 255 || !(cursorpos[chn].active)) + { + oamSub.oamMemory[chn].x = 256; + continue; + } SampleCursor *playingNote = &cursorpos[chn]; @@ -293,10 +292,11 @@ void SampleDisplay::calcCursor() looprev = true; } } - + u16 draw_cursor_at=0; if (looptype == NO_LOOP && playpos >= nsamps) { - requestRedraw(); - continue; + cursorpos[chn].active=false; + playpos = 0; + drawCursor = false; } if (looptype != NO_LOOP && looplen <= step && playpos > loopstart) @@ -305,15 +305,13 @@ void SampleDisplay::calcCursor() else playpos = loopstart + (step % looplen); - if (looptype == NO_LOOP && playpos >= nsamps) - playpos = 0; + draw_cursor_at = sampleToPixel(playpos >> 32); - u16 draw_cursor_at = sampleToPixel(playpos >> 32); + if (draw_cursor_at != 0 && cursorpos[chn].instidx == instidx && cursorpos[chn].smpidx == smpidx) + drawCursor = true; - if (draw_cursor_at < width) - cursors_xpos[chn] = draw_cursor_at; - - requestRedraw(); + if (onCursorUpdate) + onCursorUpdate(chn, draw_cursor_at, !(drawCursor && (playpos+step<=nsamps))); } } @@ -321,19 +319,21 @@ void SampleDisplay::calcCursor() void SampleDisplay::setSample(Sample *_smp, u8 _smpidx, u8 _instidx) { - smpidx = _smpidx; - instidx = _instidx; - + bool changed = false; selection_exists = false; selstart = selend = 0; if(_smp == 0) { loop_points_visible = false; } - if (_smp != smp || instidx != _instidx) - requestRedraw(); + if (smp != _smp || _smpidx != smpidx || instidx != _instidx) + changed = true; + smpidx = _smpidx; + instidx = _instidx; smp = _smp; + + if (changed) draw(); } void SampleDisplay::select_all(void) @@ -343,7 +343,7 @@ void SampleDisplay::select_all(void) selection_exists = true; selstart = 0; selend = smp->getNSamples(); - requestRedraw(); + draw(); } void SampleDisplay::clear_selection(void) @@ -353,7 +353,7 @@ void SampleDisplay::clear_selection(void) selection_exists = false; selstart = 0; selend = 0; - requestRedraw(); + draw(); } bool SampleDisplay::getSelection(u32 *startsample, u32 *endsample) @@ -376,7 +376,7 @@ void SampleDisplay::pleaseDraw(void) void SampleDisplay::setActive(void) { active = true; - requestRedraw(); + draw(); } void SampleDisplay::setInactive(void) @@ -384,20 +384,20 @@ void SampleDisplay::setInactive(void) active = false; selection_exists = false; selstart = selend = 0; - requestRedraw(); + draw(); } void SampleDisplay::setDrawMode(bool _on) { draw_mode = _on; - requestRedraw(); + draw(); } void SampleDisplay::showLoopPoints(void) { if(loop_points_visible == false) { loop_points_visible = true; - requestRedraw(); + draw(); } } @@ -406,7 +406,7 @@ void SampleDisplay::hideLoopPoints(void) if(loop_points_visible == true) { loop_points_visible = false; - requestRedraw(); + draw(); } } @@ -415,17 +415,21 @@ void SampleDisplay::setSnapToZeroCrossing(bool snap) snap_to_zero_crossings = snap; } -void SampleDisplay::requestRedraw(void) -{ - do_redraw = true; -} void SampleDisplay::reveal(void) { - requestRedraw(); + oamEnable(&oamSub); Widget::reveal(); } +void SampleDisplay::occlude(void) +{ + //if (onCursorUpdate) for (int i=0;i<16;++i) onCursorUpdate(i, cursors_xpos[i], false); + oamDisable(&oamSub); + + Widget::occlude(); +} + /* ===================== PRIVATE ===================== */ long SampleDisplay::find_zero_crossing_near(long pos) @@ -496,11 +500,9 @@ long SampleDisplay::find_zero_crossing_near(long pos) void SampleDisplay::draw(void) { - if(!isExposed() || !do_redraw) + if(!isExposed()) return; - do_redraw = false; - // Border if(active==false) { drawBorder(theme->col_outline); @@ -613,24 +615,9 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); - u16 colortable_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform); - u16 bg_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg); - + u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; + u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; data = &(base[f32toint(pos)]); s32 maxsmp = -32767, minsmp = 32767; @@ -674,24 +661,9 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); - u16 colortable_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform); - u16 bg_current = draw_cursor_here ? theme->col_env_sustain : (draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg); - + u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; + u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; data = &(base[f32toint(pos)]); s8 maxsmp = -127, minsmp = 127; @@ -867,7 +839,7 @@ void SampleDisplay::scroll(u32 newscrollpos) scrollthingypos = scrollpos * scroll_width / (disp_width - window_width); calcScrollThingy(); - requestRedraw(); + draw(); } // Calculate height and position of the scroll thingy diff --git a/arm9/source/tobkit/sampledisplay.h b/arm9/source/tobkit/sampledisplay.h index 0d32405..d743bca 100644 --- a/arm9/source/tobkit/sampledisplay.h +++ b/arm9/source/tobkit/sampledisplay.h @@ -40,7 +40,7 @@ namespace tobkit { #define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed #define MIN_SCROLLTHINGY_WIDTH 15 -#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-2) // height of the visible window +#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-3) // height of the visible window class SampleDisplay: public Widget { public: @@ -55,7 +55,6 @@ class SampleDisplay: public Widget { // Drawing request void pleaseDraw(void); - void requestRedraw(void); void reveal(void); void setSample(Sample *_smp, u8 smpidx=0, u8 instidx=255); @@ -64,8 +63,6 @@ class SampleDisplay: public Widget { void calcCursor(); void setCursorPosPtr(SampleCursor *cursorpos); - void hideCursor(void); - void showCursor(void); // Return start and end sample of selection bool getSelection(u32 *startsample, u32 *endsample); @@ -81,6 +78,10 @@ class SampleDisplay: public Widget { void setSnapToZeroCrossing(bool snap); + void setOnCursorUpdate(void (*onCursorUpdate)(u8, u8, bool)); + void (*onCursorUpdate)(u8, u8, bool); + + void occlude(void); private: // Finds a zero corssing in the sample near pos, returns sample when successful, -1 else long find_zero_crossing_near(long pos); @@ -122,13 +123,10 @@ class SampleDisplay: public Widget { bool snap_to_zero_crossings; bool draw_mode; - bool cursor_draw_mode; - bool do_redraw; u8 draw_last_x, draw_last_y; SampleCursor *cursorpos; - u32 cursors_xpos[16] = {0}; }; }; diff --git a/tobkit/include/tobkit/gui.h b/tobkit/include/tobkit/gui.h index 3b7d88c..e091617 100644 --- a/tobkit/include/tobkit/gui.h +++ b/tobkit/include/tobkit/gui.h @@ -60,9 +60,6 @@ class GUI { // Is there an overlay widget? bool hasOverlayWidget(u8 screen = SUB_SCREEN); - // Event handler for when an overlay widget is about to draw. (so we can clean up widgets underneath) - void setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)); - // Event calls void penDown(u8 x, u8 y); void penUp(u8 x, u8 y); // Remove the coordinates here! @@ -96,7 +93,6 @@ class GUI { Widget *activeWidget; u8 activeScreen; Widget *overlayWidgetMain, *overlayWidgetSub; - void (*onOverlayChanged)(u8, bool); u16 overlayShortcuts; Theme *theme; u16 bgcolor; diff --git a/tobkit/include/tobkit/theme.h b/tobkit/include/tobkit/theme.h index b2920a3..b1946ef 100644 --- a/tobkit/include/tobkit/theme.h +++ b/tobkit/include/tobkit/theme.h @@ -22,7 +22,7 @@ limitations under the License. #include "../../arm9/source/tools.h" #include -#define NUM_COLORS 112 +#define NUM_COLORS 113 namespace tobkit { @@ -142,6 +142,7 @@ struct ColorScheme { u16 col_fxkeyboard_cmd_desc_disabled; u16 col_fxkeyboard_minilabel_x; u16 col_fxkeyboard_minilabel_y; + u16 col_sample_cursor; }; }; diff --git a/tobkit/source/gui.cpp b/tobkit/source/gui.cpp index 8426312..9078fd1 100644 --- a/tobkit/source/gui.cpp +++ b/tobkit/source/gui.cpp @@ -30,7 +30,6 @@ GUI::GUI() for(i=0;i<14;++i) { shortcuts.push_back(0); } - onOverlayChanged = 0; } // Sets the theme - mandatory! @@ -104,10 +103,8 @@ void GUI::unregisterWidget(Widget *w) void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) { if(screen == SUB_SCREEN) { - onOverlayChanged(SUB_SCREEN, true); overlayWidgetSub = w; } else { - onOverlayChanged(MAIN_SCREEN, true); overlayWidgetMain = w; } overlayShortcuts = listeningButtons; @@ -119,13 +116,11 @@ void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) void GUI::unregisterOverlayWidget(u8 screen) { if(screen == SUB_SCREEN) { - onOverlayChanged(SUB_SCREEN, false); if(activeWidget==overlayWidgetSub) { activeWidget = 0; } overlayWidgetSub = 0; } else { - onOverlayChanged(MAIN_SCREEN, false); if(activeWidget==overlayWidgetMain) { activeWidget = 0; } @@ -142,11 +137,6 @@ bool GUI::hasOverlayWidget(u8 screen) return overlayWidgetMain != NULL; } -void GUI::setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)) -{ - onOverlayChanged = _onOverlayChanged; -} - // Event calls void GUI::penDown(u8 x, u8 y) { diff --git a/tobkit/source/theme.cpp b/tobkit/source/theme.cpp index a323010..5830037 100644 --- a/tobkit/source/theme.cpp +++ b/tobkit/source/theme.cpp @@ -133,6 +133,7 @@ ColorScheme::ColorScheme() { col_fxkeyboard_cmd_desc_disabled = col_dark_ctrl_disabled; col_fxkeyboard_minilabel_x = col_pv_notes &~ BIT(15); col_fxkeyboard_minilabel_y = col_pv_effect &~ BIT(15); + col_sample_cursor = col_env_sustain; } Theme::Theme(char* themepath, bool use_fat) @@ -234,7 +235,7 @@ bool Theme::parseTheme(FILE* theme_, u16* theme_cols) { // check if specific colours were specified by the theme // if not replace them with their previous colour from the same theme - if (!theme_has_key[99]) theme_cols[99] = theme_cols[3]; // Sample editor zoom buttons + if (!theme_has_key[99]) theme_cols[99] = theme_cols[3]; // Sample editor zoom buttons if (!theme_has_key[100]) theme_cols[100] = theme_cols[13]; // Message box title gradient col1 if (!theme_has_key[101]) theme_cols[101] = theme_cols[14]; // Message box title gradient col2 if (!theme_has_key[102]) theme_cols[102] = theme_cols[27]; // Message box title text @@ -248,6 +249,8 @@ bool Theme::parseTheme(FILE* theme_, u16* theme_cols) { if (!theme_has_key[109]) theme_cols[109] = theme_cols[8]; // Fxkb disabled command desc label if (!theme_has_key[110]) theme_cols[110] = theme_cols[61]; // Fxkb button param label 'X' if (!theme_has_key[111]) theme_cols[111] = theme_cols[67]; // Fxkb button param label 'Y' + if (!theme_has_key[112]) theme_cols[112] = theme_cols[38]; // Sample cursor + return true; } From 4ff04492c081409722768743fc64404a7427e205 Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Wed, 25 Feb 2026 12:22:58 +0000 Subject: [PATCH 4/7] WIP loop handles as sprites Draw the loop handles as sprites. This is still buggy (they stay there when you zoom in lol), plus need to look at the touch targets. Moved oamUpdate a bit further down to reduce input latency, etc. I'm not sure if the loop handle graphic should be an 8x8 png processed through grit (seems a bit excessive?) or just hardcoded --- arm9/source/main.cpp | 98 +++++++++++-- arm9/source/tobkit/sampledisplay.cpp | 207 ++++++++++++++++----------- 2 files changed, 211 insertions(+), 94 deletions(-) diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index eb4b341..e334ce8 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -659,12 +659,25 @@ void handleSampleChange(const u16 newsample) if (fxkb->is_visible()) updateKeyLabels(); if (!had_changes) setHasUnsavedChanges(false); + /* + printf("Selected:"); + if(smp->is16bit()) { + printf("16bit "); + } else { + printf("8bit "); + } + if(smp->getLoop() != 0) { + printf("looping "); + } + printf("Sample.\n"); + printf("length: %u\n", smp->getNSamples()); + */ } void handleCursorUpdate(u8 chn, u8 x, bool shouldHide) { bool hide = shouldHide || gui->hasOverlayWidget(SUB_SCREEN); - oamSub.oamMemory[chn].x = hide ? 199 : x-3; // can't hide sprites if we scale them, so let's just draw them offscreen + oamSub.oamMemory[chn].x = hide ? 199 : x-3; // can't hide sprites if we scale them, so let's just draw them offscreen } void volEnvSetInst(Instrument *inst) @@ -2170,6 +2183,17 @@ void destroyThemeDialog(void) redrawSubScreen(); } +// TODO this is temp, all this stuff should be in sampledisplay +void setSpritePals(void) +{ + *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + + // palette index 1 + *(SPRITE_PALETTE_SUB+2+16) = settings->getTheme()->col_outline; + *(SPRITE_PALETTE_SUB+3+16) = settings->getTheme()->col_loop; + *(SPRITE_PALETTE_SUB+1+16) = settings->getTheme()->col_loop; +} + void reloadSkin(void) { gui->setTheme(settings->getTheme(), settings->getTheme()->col_bg); @@ -2182,7 +2206,7 @@ void reloadSkin(void) dmaFillWords(colcol, sub_vram + (256 * y) + 224, (256 - 224) * 2); } - *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + setSpritePals(); gui->draw(); redrawSubScreen(); @@ -3393,7 +3417,8 @@ void setupGUI(bool dldi_enabled) fxkb = new FXKeyboard(0, 152, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram, onFxKeyPressed, false); fxkb->set_overdraw(false); - *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + setSpritePals(); + pixmaplogo = new GradientIcon(98, 1, 80, 17, (const u32*) nitrotracker_logo_raw, &sub_vram); @@ -4232,7 +4257,6 @@ void VblankHandler(void) u16 keysheld = keysHeld(); touchRead(&touch); - oamUpdate(&oamSub); if(keysdown & KEY_TOUCH) { @@ -4287,6 +4311,9 @@ void VblankHandler(void) fastscroll = false; } + oamUpdate(&oamSub); + + // Easy Piano pak handling logic if (pianoIsInserted()) { @@ -4481,13 +4508,15 @@ int main(int argc, char **argv) { bgWindowEnable(piano_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); bgWindowEnable(typewriter_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); - windowSetBoundsSub(WINDOW_0, 4, 24, 4+128, 23+61); // sampledisplay x1,y1,x2,y2 + windowSetBoundsSub(WINDOW_0, 5, 24, 5+129, 23+61); // sampledisplay x1,y1,x2,y2 oamWindowEnable(&oamSub, WINDOW_0); - u16 *gfxSub = oamAllocateGfx(&oamSub, SpriteSize_16x32, SpriteColorFormat_16Color); + u16 *gfxSampleCursor = oamAllocateGfx(&oamSub, SpriteSize_16x32, SpriteColorFormat_16Color); - *(gfxSub+64)=1; - // *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + u16 *gfxLoopHandles = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_16Color); + + *(gfxSampleCursor+64)=1; + oamSub.oamRotationMemory[0].vdy = 0; // max y scale for (int c=0;c<16;++c) @@ -4495,10 +4524,58 @@ int main(int argc, char **argv) { oamSet(&oamSub, c, 256, 23, 0, 0, SpriteSize_16x32, SpriteColorFormat_16Color, - gfxSub, + gfxSampleCursor, 0, true, false, false, false, false); } + const unsigned int loophandleTiles[8] __attribute__((aligned(4)))= + { + 0x22000000, + 0x33200000, + 0x33320000, + 0x33332000, + 0x33333200, + 0x33333320, + 0x33333332, + 0x33333332 + }; + + memcpy(gfxLoopHandles, loophandleTiles, 32); + + // handles + for (int i=16;i<20;++i) + { + oamSet(&oamSub, i, + 50, 25, + 0, + 1, + SpriteSize_8x8, SpriteColorFormat_16Color, + gfxLoopHandles, + -1, + false, + false, + i % 2 == 1, i > 17, // h-flip every other handle, v-flip the last two handles + false); + } + + // reuse cursors as part of the loop handles + for (int i=20;i<22;++i) + { + oamSet(&oamSub, i, + 50, 25, + 0, + 1, + SpriteSize_16x32, SpriteColorFormat_16Color, + gfxSampleCursor, + 0, + true, + false, + false, false, + false); + } + + + //for (int i=0;i<16;++i) oamSetHidden(&oamSub, i, true); // using hide=true in oamSet makes the draw broken fsr // Special effects @@ -4582,7 +4659,8 @@ int main(int argc, char **argv) { applySettings(); - *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; + + setSong(song); #ifndef DEBUG diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index 146e08d..8199e39 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -71,6 +71,8 @@ void SampleDisplay::penDown(u8 px, u8 py) u32 loop_start_pos = sampleToPixel(smp->getLoopStart());//smp->getLoopStart() * (width-2) / smp->getNSamples(); u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength());//(smp->getLoopStart() + smp->getLoopLength()) * (width-2) / smp->getNSamples(); + + if(isInRect(px-x, py-y, std::max((s32)0, (s32)loop_start_pos - (s32)LOOP_TRIANGLE_SIZE), DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE, loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT+2)) { @@ -183,6 +185,7 @@ void SampleDisplay::penMove(u8 px, u8 py) } smp->setLoopStartAndLength(newstart, newlength); } + else if(pen_on_scrollthingy) { scrollthingypos = ntxm_clamp(px - x - pen_x_on_scrollthingy - SCROLLBUTTON_HEIGHT, 0, width - 2*SCROLLBUTTON_HEIGHT+2 - scrollthingywidth); @@ -615,7 +618,7 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); + bool draw_selection_here = (draw_selection && i >= selleft && i <= selright); u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; data = &(base[f32toint(pos)]); @@ -661,7 +664,7 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); + bool draw_selection_here = (draw_selection && i >= selleft && i <= selright); u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; data = &(base[f32toint(pos)]); @@ -705,93 +708,129 @@ void SampleDisplay::draw(void) // // Loop Points // + if( (loop_points_visible) && (smp->getLoop() != NO_LOOP) && !draw_mode ) { - s32 loop_start_pos = sampleToPixel(smp->getLoopStart()); - s32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); - - // Loop Start - - if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) { - // Line - for(u8 i=1; icol_loop; - - /* unused - u8 cutoff = 0; - if(loop_start_pos < 1+LOOP_TRIANGLE_SIZE) - cutoff = 1+LOOP_TRIANGLE_SIZE - loop_start_pos; - */ - - // Left Triangle - if(loop_start_pos > 1 + LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_start_pos-2, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - - for(u8 i=0; icol_loop); - drawPixel(loop_start_pos-i-3, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); - } - - drawHLine(loop_start_pos-LOOP_TRIANGLE_SIZE+1, DRAW_HEIGHT, LOOP_TRIANGLE_SIZE-1, - theme->col_loop); - drawPixel(loop_start_pos-LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); - } - - // Right Triangle - if(loop_start_pos < width - 2 - LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_start_pos+1, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - for(u8 i=0; icol_loop); - drawPixel(loop_start_pos+3+i, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); - } - drawHLine(loop_start_pos+1, DRAW_HEIGHT-LOOP_TRIANGLE_SIZE+LOOP_TRIANGLE_SIZE, LOOP_TRIANGLE_SIZE-1, - theme->col_loop); - drawPixel(loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); - } - } - - // Loop End + u32 loop_start_pos = sampleToPixel(smp->getLoopStart()); + u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); - if( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ) { - // Line - for(u8 i=1; icol_loop; - - // Left Triangle - if(loop_end_pos > 1 + LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_end_pos-LOOP_TRIANGLE_SIZE+1, 1, LOOP_TRIANGLE_SIZE-1, - theme->col_loop); - drawPixel(loop_end_pos-LOOP_TRIANGLE_SIZE, 1, theme->col_outline); - - for(u8 i=0; icol_loop); - drawPixel(loop_end_pos-1-LOOP_TRIANGLE_SIZE+i+1, 2+i, theme->col_outline); - } - - drawHLine(loop_end_pos-2, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - } - - // Right Triangle - if(loop_end_pos < width-1-LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_end_pos+1, 1, LOOP_TRIANGLE_SIZE-1, theme->col_loop); - drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE, 1, theme->col_outline); - - for(u8 i=0; icol_loop); - drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE-i, 2+i, theme->col_outline); - } - - drawHLine(loop_end_pos+1, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - } + if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) + { + oamSetXY(&oamSub, 16, loop_start_pos-4, DRAW_HEIGHT+18); + oamSetXY(&oamSub, 17, loop_start_pos-4+8-1, DRAW_HEIGHT+18); + oamSetXY(&oamSub, 18, loop_end_pos-4, y); + oamSetXY(&oamSub, 19, loop_end_pos-4+8-1, y); + oamSetXY(&oamSub, 20, loop_start_pos-5, y); + oamSetXY(&oamSub, 21, loop_end_pos-5, y); } + else + goto delt; + + } + else + { + delt: + oamSetXY(&oamSub, 20, width, y); + oamSetXY(&oamSub, 21, width, y); } + oamSetHidden(&oamSub, 16, !loop_points_visible); + oamSetHidden(&oamSub, 17, !loop_points_visible); + oamSetHidden(&oamSub, 18, !loop_points_visible); + oamSetHidden(&oamSub, 19, !loop_points_visible); + // oamSetHidden(&oamSub, 20, !loop_points_visible); + // oamSetHidden(&oamSub, 21, !loop_points_visible); + + + // s32 loop_start_pos = sampleToPixel(smp->getLoopStart()); + // s32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); + + // // Loop Start + + + // if(1) + // { + // if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) { + // // Line + // for(u8 i=1; icol_loop; + + // /* unused + // u8 cutoff = 0; + // if(loop_start_pos < 1+LOOP_TRIANGLE_SIZE) + // cutoff = 1+LOOP_TRIANGLE_SIZE - loop_start_pos; + // */ + + // // Left Triangle + // if(loop_start_pos > 1 + LOOP_TRIANGLE_SIZE) + // { + // drawHLine(loop_start_pos-2, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); + + // for(u8 i=0; icol_loop); + // drawPixel(loop_start_pos-i-3, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); + // } + + // drawHLine(loop_start_pos-LOOP_TRIANGLE_SIZE+1, DRAW_HEIGHT, LOOP_TRIANGLE_SIZE-1, + // theme->col_loop); + // drawPixel(loop_start_pos-LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); + // } + + // // Right Triangle + // if(loop_start_pos < width - 2 - LOOP_TRIANGLE_SIZE) + // { + // drawHLine(loop_start_pos+1, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); + // for(u8 i=0; icol_loop); + // drawPixel(loop_start_pos+3+i, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); + // } + // drawHLine(loop_start_pos+1, DRAW_HEIGHT-LOOP_TRIANGLE_SIZE+LOOP_TRIANGLE_SIZE, LOOP_TRIANGLE_SIZE-1, + // theme->col_loop); + // drawPixel(loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); + // } + // } + // } + + + // // Loop End + + // if( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ) { + // // Line + // for(u8 i=1; icol_loop; + + // // Left Triangle + // if(loop_end_pos > 1 + LOOP_TRIANGLE_SIZE) + // { + // drawHLine(loop_end_pos-LOOP_TRIANGLE_SIZE+1, 1, LOOP_TRIANGLE_SIZE-1, + // theme->col_loop); + // drawPixel(loop_end_pos-LOOP_TRIANGLE_SIZE, 1, theme->col_outline); + + // for(u8 i=0; icol_loop); + // drawPixel(loop_end_pos-1-LOOP_TRIANGLE_SIZE+i+1, 2+i, theme->col_outline); + // } + + // drawHLine(loop_end_pos-2, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); + // } + + // // Right Triangle + // if(loop_end_pos < width-1-LOOP_TRIANGLE_SIZE) + // { + // drawHLine(loop_end_pos+1, 1, LOOP_TRIANGLE_SIZE-1, theme->col_loop); + // drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE, 1, theme->col_outline); + + // for(u8 i=0; icol_loop); + // drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE-i, 2+i, theme->col_outline); + // } + + // drawHLine(loop_end_pos+1, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); + // } + // } + // } // // Zoom buttons From d3c28b183dbab7a2366e0627c6a209a0c6067506 Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Wed, 25 Feb 2026 12:34:43 +0000 Subject: [PATCH 5/7] remove useless debug goto,fix loop handle pos --- arm9/source/tobkit/sampledisplay.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index 8199e39..ede72c3 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -709,27 +709,25 @@ void SampleDisplay::draw(void) // Loop Points // + u32 loop_start_pos = sampleToPixel(smp->getLoopStart()); + u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); + if( (loop_points_visible) && (smp->getLoop() != NO_LOOP) && !draw_mode ) { - u32 loop_start_pos = sampleToPixel(smp->getLoopStart()); - u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); + if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) { - oamSetXY(&oamSub, 16, loop_start_pos-4, DRAW_HEIGHT+18); - oamSetXY(&oamSub, 17, loop_start_pos-4+8-1, DRAW_HEIGHT+18); - oamSetXY(&oamSub, 18, loop_end_pos-4, y); - oamSetXY(&oamSub, 19, loop_end_pos-4+8-1, y); - oamSetXY(&oamSub, 20, loop_start_pos-5, y); - oamSetXY(&oamSub, 21, loop_end_pos-5, y); + oamSetXY(&oamSub, 16, loop_start_pos-2, DRAW_HEIGHT+18); + oamSetXY(&oamSub, 17, loop_start_pos-2+8-1, DRAW_HEIGHT+18); + oamSetXY(&oamSub, 18, loop_end_pos-2, y); + oamSetXY(&oamSub, 19, loop_end_pos-2+8-1, y); + oamSetXY(&oamSub, 20, loop_start_pos-2-1, y); + oamSetXY(&oamSub, 21, loop_end_pos-2-1, y); } - else - goto delt; - } else { - delt: oamSetXY(&oamSub, 20, width, y); oamSetXY(&oamSub, 21, width, y); } From ac867e478ec9002c71c98dd756ea8f47544ce600 Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Wed, 25 Feb 2026 12:42:39 +0000 Subject: [PATCH 6/7] Fix buggy loop handle draw on zoom --- arm9/source/main.cpp | 4 +- arm9/source/tobkit/sampledisplay.cpp | 123 ++++----------------------- 2 files changed, 19 insertions(+), 108 deletions(-) diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index e334ce8..b70d811 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -4546,7 +4546,7 @@ int main(int argc, char **argv) { for (int i=16;i<20;++i) { oamSet(&oamSub, i, - 50, 25, + 199, 25, 0, 1, SpriteSize_8x8, SpriteColorFormat_16Color, @@ -4562,7 +4562,7 @@ int main(int argc, char **argv) { for (int i=20;i<22;++i) { oamSet(&oamSub, i, - 50, 25, + 199, 0, 0, 1, SpriteSize_16x32, SpriteColorFormat_16Color, diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index ede72c3..dbc0db3 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -712,123 +712,34 @@ void SampleDisplay::draw(void) u32 loop_start_pos = sampleToPixel(smp->getLoopStart()); u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); + bool draw_loop_end = ( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ); + bool draw_loop_start = (loop_start_pos >= 0) && (loop_start_pos <= width-2); + if( (loop_points_visible) && (smp->getLoop() != NO_LOOP) && !draw_mode ) { - - - if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) + if(draw_loop_start) { oamSetXY(&oamSub, 16, loop_start_pos-2, DRAW_HEIGHT+18); oamSetXY(&oamSub, 17, loop_start_pos-2+8-1, DRAW_HEIGHT+18); + oamSetXY(&oamSub, 20, loop_start_pos-2-1, y); + } + else + oamSetXY(&oamSub, 20, width+1, y); + + if(draw_loop_end) + { oamSetXY(&oamSub, 18, loop_end_pos-2, y); oamSetXY(&oamSub, 19, loop_end_pos-2+8-1, y); - oamSetXY(&oamSub, 20, loop_start_pos-2-1, y); oamSetXY(&oamSub, 21, loop_end_pos-2-1, y); } + else + oamSetXY(&oamSub, 21, width+1, y); } - else - { - oamSetXY(&oamSub, 20, width, y); - oamSetXY(&oamSub, 21, width, y); - } - oamSetHidden(&oamSub, 16, !loop_points_visible); - oamSetHidden(&oamSub, 17, !loop_points_visible); - oamSetHidden(&oamSub, 18, !loop_points_visible); - oamSetHidden(&oamSub, 19, !loop_points_visible); - // oamSetHidden(&oamSub, 20, !loop_points_visible); - // oamSetHidden(&oamSub, 21, !loop_points_visible); - - - // s32 loop_start_pos = sampleToPixel(smp->getLoopStart()); - // s32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); - - // // Loop Start - - - // if(1) - // { - // if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) { - // // Line - // for(u8 i=1; icol_loop; - - // /* unused - // u8 cutoff = 0; - // if(loop_start_pos < 1+LOOP_TRIANGLE_SIZE) - // cutoff = 1+LOOP_TRIANGLE_SIZE - loop_start_pos; - // */ - - // // Left Triangle - // if(loop_start_pos > 1 + LOOP_TRIANGLE_SIZE) - // { - // drawHLine(loop_start_pos-2, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - - // for(u8 i=0; icol_loop); - // drawPixel(loop_start_pos-i-3, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); - // } - - // drawHLine(loop_start_pos-LOOP_TRIANGLE_SIZE+1, DRAW_HEIGHT, LOOP_TRIANGLE_SIZE-1, - // theme->col_loop); - // drawPixel(loop_start_pos-LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); - // } - - // // Right Triangle - // if(loop_start_pos < width - 2 - LOOP_TRIANGLE_SIZE) - // { - // drawHLine(loop_start_pos+1, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - // for(u8 i=0; icol_loop); - // drawPixel(loop_start_pos+3+i, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); - // } - // drawHLine(loop_start_pos+1, DRAW_HEIGHT-LOOP_TRIANGLE_SIZE+LOOP_TRIANGLE_SIZE, LOOP_TRIANGLE_SIZE-1, - // theme->col_loop); - // drawPixel(loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); - // } - // } - // } - - // // Loop End - - // if( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ) { - // // Line - // for(u8 i=1; icol_loop; - - // // Left Triangle - // if(loop_end_pos > 1 + LOOP_TRIANGLE_SIZE) - // { - // drawHLine(loop_end_pos-LOOP_TRIANGLE_SIZE+1, 1, LOOP_TRIANGLE_SIZE-1, - // theme->col_loop); - // drawPixel(loop_end_pos-LOOP_TRIANGLE_SIZE, 1, theme->col_outline); - - // for(u8 i=0; icol_loop); - // drawPixel(loop_end_pos-1-LOOP_TRIANGLE_SIZE+i+1, 2+i, theme->col_outline); - // } - - // drawHLine(loop_end_pos-2, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - // } - - // // Right Triangle - // if(loop_end_pos < width-1-LOOP_TRIANGLE_SIZE) - // { - // drawHLine(loop_end_pos+1, 1, LOOP_TRIANGLE_SIZE-1, theme->col_loop); - // drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE, 1, theme->col_outline); - - // for(u8 i=0; icol_loop); - // drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE-i, 2+i, theme->col_outline); - // } - - // drawHLine(loop_end_pos+1, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - // } - // } - // } + oamSetHidden(&oamSub, 16, !draw_loop_start); + oamSetHidden(&oamSub, 17, !draw_loop_start); + oamSetHidden(&oamSub, 18, !draw_loop_end); + oamSetHidden(&oamSub, 19, !draw_loop_end); // // Zoom buttons From ceaad84cb414fe1c525f332457ebb8019c30e212 Mon Sep 17 00:00:00 2001 From: R Ferreira Date: Wed, 25 Feb 2026 13:34:42 +0000 Subject: [PATCH 7/7] a bit of cleanup --- arm9/source/main.cpp | 100 +++---------------------- arm9/source/tobkit/sampledisplay.cpp | 108 ++++++++++++++++++++++----- arm9/source/tobkit/sampledisplay.h | 24 ++++-- tobkit/include/tobkit/gui.h | 5 +- tobkit/source/gui.cpp | 16 ++-- 5 files changed, 128 insertions(+), 125 deletions(-) diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index b70d811..ba21a89 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -674,12 +674,6 @@ void handleSampleChange(const u16 newsample) */ } -void handleCursorUpdate(u8 chn, u8 x, bool shouldHide) -{ - bool hide = shouldHide || gui->hasOverlayWidget(SUB_SCREEN); - oamSub.oamMemory[chn].x = hide ? 199 : x-3; // can't hide sprites if we scale them, so let's just draw them offscreen -} - void volEnvSetInst(Instrument *inst) { bool had_unsaved = state->unsaved_changes; @@ -2183,16 +2177,6 @@ void destroyThemeDialog(void) redrawSubScreen(); } -// TODO this is temp, all this stuff should be in sampledisplay -void setSpritePals(void) -{ - *(SPRITE_PALETTE_SUB+1) = settings->getTheme()->col_sample_cursor; - - // palette index 1 - *(SPRITE_PALETTE_SUB+2+16) = settings->getTheme()->col_outline; - *(SPRITE_PALETTE_SUB+3+16) = settings->getTheme()->col_loop; - *(SPRITE_PALETTE_SUB+1+16) = settings->getTheme()->col_loop; -} void reloadSkin(void) { @@ -2206,8 +2190,6 @@ void reloadSkin(void) dmaFillWords(colcol, sub_vram + (256 * y) + 224, (256 - 224) * 2); } - setSpritePals(); - gui->draw(); redrawSubScreen(); setRecordMode(state->recording); @@ -3401,6 +3383,15 @@ void sampleDrawToggle(bool on) sampledisplay->setDrawMode(on); } +void handleOverlayWidgetChange(u8 screen, bool visible) +{ + if (screen == SUB_SCREEN) + { + if (visible) oamDisable(&oamSub); + else oamEnable(&oamSub); + } +} + #define RIGHT_SIDE_BUTTON_WIDTH 30 #define RIGHT_SIDE_BUTTON_X 225 @@ -3408,7 +3399,7 @@ void setupGUI(bool dldi_enabled) { gui = new GUI(); gui->setTheme(settings->getTheme(), settings->getTheme()->col_bg); - + gui->setOnOverlayChanged(handleOverlayWidgetChange); kb = new Piano(0, 152, 224, 40, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram); kb->set_overdraw(false); kb->registerNoteCallback(handleNoteStroke); @@ -3416,9 +3407,7 @@ void setupGUI(bool dldi_enabled) fxkb = new FXKeyboard(0, 152, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram, onFxKeyPressed, false); fxkb->set_overdraw(false); - - setSpritePals(); - + pixmaplogo = new GradientIcon(98, 1, 80, 17, (const u32*) nitrotracker_logo_raw, &sub_vram); @@ -4500,6 +4489,7 @@ int main(int argc, char **argv) { int sub_bg = bgInitSub(2, BgType_Bmp16, BgSize_B16_256x256, 2, 0); bgSetPriority(sub_bg, 0); + // Sample display cursors and loop handles oamInit(&oamSub, SpriteMapping_1D_32, false); windowEnableSub(WINDOW_0); @@ -4511,72 +4501,7 @@ int main(int argc, char **argv) { windowSetBoundsSub(WINDOW_0, 5, 24, 5+129, 23+61); // sampledisplay x1,y1,x2,y2 oamWindowEnable(&oamSub, WINDOW_0); - u16 *gfxSampleCursor = oamAllocateGfx(&oamSub, SpriteSize_16x32, SpriteColorFormat_16Color); - - u16 *gfxLoopHandles = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_16Color); - - *(gfxSampleCursor+64)=1; - - oamSub.oamRotationMemory[0].vdy = 0; // max y scale - - for (int c=0;c<16;++c) - { - oamSet(&oamSub, c, 256, 23, 0, 0, - SpriteSize_16x32, - SpriteColorFormat_16Color, - gfxSampleCursor, - 0, true, false, false, false, false); - } - - const unsigned int loophandleTiles[8] __attribute__((aligned(4)))= - { - 0x22000000, - 0x33200000, - 0x33320000, - 0x33332000, - 0x33333200, - 0x33333320, - 0x33333332, - 0x33333332 - }; - - memcpy(gfxLoopHandles, loophandleTiles, 32); - - // handles - for (int i=16;i<20;++i) - { - oamSet(&oamSub, i, - 199, 25, - 0, - 1, - SpriteSize_8x8, SpriteColorFormat_16Color, - gfxLoopHandles, - -1, - false, - false, - i % 2 == 1, i > 17, // h-flip every other handle, v-flip the last two handles - false); - } - - // reuse cursors as part of the loop handles - for (int i=20;i<22;++i) - { - oamSet(&oamSub, i, - 199, 0, - 0, - 1, - SpriteSize_16x32, SpriteColorFormat_16Color, - gfxSampleCursor, - 0, - true, - false, - false, false, - false); - } - - - //for (int i=0;i<16;++i) oamSetHidden(&oamSub, i, true); // using hide=true in oamSet makes the draw broken fsr // Special effects #ifdef DEBUG @@ -4653,7 +4578,6 @@ int main(int argc, char **argv) { SampleCursor *scursors = (SampleCursor*)ntxm_ccalloc(MAX_CHANNELS, sizeof(SampleCursor)); CommandSetCursorPosPtr(scursors); sampledisplay->setCursorPosPtr((SampleCursor*)memUncached(scursors)); - sampledisplay->setOnCursorUpdate(handleCursorUpdate); action_buffer->register_change_callback({&actionBufferChangeCallback}); diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index dbc0db3..e766249 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -45,17 +45,74 @@ SampleDisplay::SampleDisplay(u8 _x, u8 _y, u8 _width, u8 _height, u16 **_vram, S scrollthingypos(0), scrollthingywidth(width-2*SCROLLBUTTON_HEIGHT+2), pen_x_on_scrollthingy(0), zoom_level(0), scrollpos(0), snap_to_zero_crossings(true), draw_mode(false) { + gfxSampleCursor = oamAllocateGfx(&oamSub, SpriteSize_16x32, SpriteColorFormat_16Color); -} + gfxLoopHandles = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_16Color); + + *(gfxSampleCursor+64)=1; + + oamSub.oamRotationMemory[0].vdy = 0; // max y scale -SampleDisplay::~SampleDisplay(void) -{ + for (int c=0;c<16;++c) + { + oamSet(&oamSub, c, 256, 23, 0, 0, + SpriteSize_16x32, + SpriteColorFormat_16Color, + gfxSampleCursor, + 0, true, false, false, false, false); + } + + const unsigned int loophandleTiles[8] __attribute__((aligned(4)))= + { + 0x22000000, + 0x33200000, + 0x33320000, + 0x33332000, + 0x33333200, + 0x33333320, + 0x33333332, + 0x33333332 + }; + + memcpy(gfxLoopHandles, loophandleTiles, 32); + + // handles + for (int i=SPR_LOOPHANDLE_1_L;i<=SPR_LOOPHANDLE_2_R;++i) + { + oamSet(&oamSub, i, + 199, 25, + 0, + 1, + SpriteSize_8x8, SpriteColorFormat_16Color, + gfxLoopHandles, + -1, + false, + false, + i % 2 == 1, i > 17, // h-flip every other handle, v-flip the last two handles + false); + } + // reuse cursors as part of the loop handles + for (int i=SPR_LOOPLINE_1;i<=SPR_LOOPLINE_2;++i) + { + oamSet(&oamSub, i, + 199, 0, + 0, + 1, + SpriteSize_16x32, SpriteColorFormat_16Color, + gfxSampleCursor, + 0, + true, + false, + false, false, + false); + } } -void SampleDisplay::setOnCursorUpdate(void(*_onCursorUpdate)(u8, u8, bool)) +SampleDisplay::~SampleDisplay(void) { - onCursorUpdate = _onCursorUpdate; + oamFreeGfx(&oamSub, gfxSampleCursor); + oamFreeGfx(&oamSub, gfxLoopHandles); } void SampleDisplay::penDown(u8 px, u8 py) @@ -313,8 +370,8 @@ void SampleDisplay::calcCursor() if (draw_cursor_at != 0 && cursorpos[chn].instidx == instidx && cursorpos[chn].smpidx == smpidx) drawCursor = true; - if (onCursorUpdate) - onCursorUpdate(chn, draw_cursor_at, !(drawCursor && (playpos+step<=nsamps))); + + oamSub.oamMemory[chn].x = !drawCursor ? 199 : draw_cursor_at-3; } } @@ -390,6 +447,18 @@ void SampleDisplay::setInactive(void) draw(); } +void SampleDisplay::setTheme(Theme *theme_, u16 bgcolor_) +{ + *(SPRITE_PALETTE_SUB+1) = theme_->col_sample_cursor; + + // palette index 1 + *(SPRITE_PALETTE_SUB+2+16) = theme_->col_outline; + *(SPRITE_PALETTE_SUB+3+16) = theme_->col_loop; + *(SPRITE_PALETTE_SUB+1+16) = theme_->col_loop; + + Widget::setTheme(theme_, bgcolor_); +} + void SampleDisplay::setDrawMode(bool _on) { draw_mode = _on; @@ -427,7 +496,6 @@ void SampleDisplay::reveal(void) void SampleDisplay::occlude(void) { - //if (onCursorUpdate) for (int i=0;i<16;++i) onCursorUpdate(i, cursors_xpos[i], false); oamDisable(&oamSub); Widget::occlude(); @@ -719,27 +787,27 @@ void SampleDisplay::draw(void) { if(draw_loop_start) { - oamSetXY(&oamSub, 16, loop_start_pos-2, DRAW_HEIGHT+18); - oamSetXY(&oamSub, 17, loop_start_pos-2+8-1, DRAW_HEIGHT+18); - oamSetXY(&oamSub, 20, loop_start_pos-2-1, y); + oamSetXY(&oamSub, SPR_LOOPHANDLE_1_L, loop_start_pos-2, DRAW_HEIGHT+18); + oamSetXY(&oamSub, SPR_LOOPHANDLE_1_R, loop_start_pos-2+8-1, DRAW_HEIGHT+18); + oamSetXY(&oamSub, SPR_LOOPLINE_1, loop_start_pos-2-1, y); } else - oamSetXY(&oamSub, 20, width+1, y); + oamSetXY(&oamSub, SPR_LOOPLINE_1, width+1, y); if(draw_loop_end) { - oamSetXY(&oamSub, 18, loop_end_pos-2, y); - oamSetXY(&oamSub, 19, loop_end_pos-2+8-1, y); - oamSetXY(&oamSub, 21, loop_end_pos-2-1, y); + oamSetXY(&oamSub, SPR_LOOPHANDLE_2_L, loop_end_pos-2, y); + oamSetXY(&oamSub, SPR_LOOPHANDLE_2_R, loop_end_pos-2+8-1, y); + oamSetXY(&oamSub, SPR_LOOPLINE_2, loop_end_pos-2-1, y); } else - oamSetXY(&oamSub, 21, width+1, y); + oamSetXY(&oamSub, SPR_LOOPLINE_2, width+1, y); } - oamSetHidden(&oamSub, 16, !draw_loop_start); - oamSetHidden(&oamSub, 17, !draw_loop_start); - oamSetHidden(&oamSub, 18, !draw_loop_end); - oamSetHidden(&oamSub, 19, !draw_loop_end); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_1_L, !draw_loop_start); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_1_R, !draw_loop_start); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_2_L, !draw_loop_end); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_2_R, !draw_loop_end); // // Zoom buttons diff --git a/arm9/source/tobkit/sampledisplay.h b/arm9/source/tobkit/sampledisplay.h index d743bca..94ef5b7 100644 --- a/arm9/source/tobkit/sampledisplay.h +++ b/arm9/source/tobkit/sampledisplay.h @@ -33,14 +33,22 @@ namespace tobkit { #define LOOP_TRIANGLE_SIZE 8 #define SNAP_TO_ZERO_CROSSING_RADIUS 32 // Search 32 samples to the left and to the right to find a zero crossing -#define SCROLLBAR_WIDTH 9 -#define SCROLLBUTTON_HEIGHT 9 +#define SCROLLBAR_WIDTH 9 +#define SCROLLBUTTON_HEIGHT 9 #define SAMPLE_MAX_ZOOM 16 -#define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed -#define MIN_SCROLLTHINGY_WIDTH 15 -#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-3) // height of the visible window +#define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed +#define MIN_SCROLLTHINGY_WIDTH 15 +#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-3) // height of the visible window + +#define SPR_SCURSOR(n) (n) +#define SPR_LOOPHANDLE_1_L 16 +#define SPR_LOOPHANDLE_1_R 17 +#define SPR_LOOPHANDLE_2_L 18 +#define SPR_LOOPHANDLE_2_R 19 +#define SPR_LOOPLINE_1 20 +#define SPR_LOOPLINE_2 21 class SampleDisplay: public Widget { public: @@ -71,6 +79,8 @@ class SampleDisplay: public Widget { void setActive(void); void setInactive(void); + void setTheme(Theme *theme_, u16 bgcolor_); + void setDrawMode(bool _on); void showLoopPoints(void); @@ -78,9 +88,6 @@ class SampleDisplay: public Widget { void setSnapToZeroCrossing(bool snap); - void setOnCursorUpdate(void (*onCursorUpdate)(u8, u8, bool)); - void (*onCursorUpdate)(u8, u8, bool); - void occlude(void); private: // Finds a zero corssing in the sample near pos, returns sample when successful, -1 else @@ -127,6 +134,7 @@ class SampleDisplay: public Widget { u8 draw_last_x, draw_last_y; SampleCursor *cursorpos; + u16 *gfxSampleCursor, *gfxLoopHandles; }; }; diff --git a/tobkit/include/tobkit/gui.h b/tobkit/include/tobkit/gui.h index e091617..7ac6241 100644 --- a/tobkit/include/tobkit/gui.h +++ b/tobkit/include/tobkit/gui.h @@ -57,8 +57,8 @@ class GUI { // Remove the overlay widget void unregisterOverlayWidget(u8 screen = SUB_SCREEN); - // Is there an overlay widget? - bool hasOverlayWidget(u8 screen = SUB_SCREEN); + // Event handler for when an overlay widget is about to draw. (so we can clean up widgets underneath) + void setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)); // Event calls void penDown(u8 x, u8 y); @@ -93,6 +93,7 @@ class GUI { Widget *activeWidget; u8 activeScreen; Widget *overlayWidgetMain, *overlayWidgetSub; + void (*onOverlayChanged)(u8, bool); u16 overlayShortcuts; Theme *theme; u16 bgcolor; diff --git a/tobkit/source/gui.cpp b/tobkit/source/gui.cpp index 9078fd1..f532a02 100644 --- a/tobkit/source/gui.cpp +++ b/tobkit/source/gui.cpp @@ -23,7 +23,7 @@ using namespace tobkit; /* ===================== PUBLIC ===================== */ GUI::GUI() - :activeWidget(0), activeScreen(SUB_SCREEN), overlayWidgetMain(0), + :activeWidget(0), activeScreen(SUB_SCREEN), onOverlayChanged(0), overlayWidgetMain(0), overlayWidgetSub(0), overlayShortcuts(0) { u8 i; @@ -103,8 +103,10 @@ void GUI::unregisterWidget(Widget *w) void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) { if(screen == SUB_SCREEN) { + onOverlayChanged(SUB_SCREEN, true); overlayWidgetSub = w; } else { + onOverlayChanged(MAIN_SCREEN, true); overlayWidgetMain = w; } overlayShortcuts = listeningButtons; @@ -116,11 +118,13 @@ void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) void GUI::unregisterOverlayWidget(u8 screen) { if(screen == SUB_SCREEN) { + onOverlayChanged(SUB_SCREEN, false); if(activeWidget==overlayWidgetSub) { activeWidget = 0; } overlayWidgetSub = 0; } else { + onOverlayChanged(MAIN_SCREEN, false); if(activeWidget==overlayWidgetMain) { activeWidget = 0; } @@ -129,13 +133,11 @@ void GUI::unregisterOverlayWidget(u8 screen) overlayShortcuts = 0; } -bool GUI::hasOverlayWidget(u8 screen) + +void GUI::setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)) { - if (screen == SUB_SCREEN) - return overlayWidgetSub != NULL; - else - return overlayWidgetMain != NULL; -} + onOverlayChanged = _onOverlayChanged; +} // Event calls void GUI::penDown(u8 x, u8 y)