(Preliminary) sample cursor (nt)#205
Conversation
arm9/source/tobkit/sampledisplay.h
Outdated
| #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 |
There was a problem hiding this comment.
Fixes an issue where the sample display draws over 1px of the horizontal scrollbar
|
|
||
| void cursorTimerHandler(void) | ||
| { | ||
| sampledisplay->calcCursor(); |
There was a problem hiding this comment.
admittedly not much better than just doing this in vblank, although this results in less drift anyway. i tried calculating using ticks but couldn't get it as accurate
|
|
||
| void startCursorTimer(void) | ||
| { | ||
| TIMER1_DATA = TIMER_FREQ_64(60); // Call handler every frame |
There was a problem hiding this comment.
per libnds timers.h timer1 doesn't seem to be used for anything else so i presume it's ok
tobkit/source/gui.cpp
Outdated
| overlayShortcuts = 0; | ||
| } | ||
|
|
||
| bool GUI::hasOverlayWidget(u8 screen) |
There was a problem hiding this comment.
if we use a sprite for the cursor we could do away with setOnOverlayChanged below as we wouldn't need to do a final draw to hide the cursor, but hasOverlayWidget would still be useful regardless (so we know when to hide it), in addition to potentially being useful for the lbpot being occluded by the typewriter thing
|
|
||
| Sample *smp; | ||
|
|
||
| u8 smpidx, instidx; |
There was a problem hiding this comment.
needed so we only draw the relevant cursor. i considered doing this as a single u16 instsmp_idx ((instidx << 8) | smpidx)) but it seemed unnecessarily elaborate
| continue; | ||
| } | ||
|
|
||
| if (looptype != NO_LOOP && looplen <= step && playpos > loopstart) |
There was a problem hiding this comment.
this section isn't technically necessary but is for the case where the length of the loop is less than the step size of the cursor (ie the cursor is 'trapped' in a really small loop), so it draws the cursor visibly between the two loop points, rather than being hidden by one of the loop handles
arm9/source/tobkit/sampledisplay.cpp
Outdated
| u16 draw_cursor_at = sampleToPixel(playpos >> 32); | ||
|
|
||
| if (draw_cursor_at < width) | ||
| cursors_xpos[chn] = draw_cursor_at; |
There was a problem hiding this comment.
Alternatively this could have been done in draw, calculating the x position directly, admittedly cursors_xpos is a little redundant
7d5c745 to
b3a9271
Compare
b3a9271 to
195a067
Compare
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
| for(s32 i=1; i<s32(width-1); ++i) | ||
| { | ||
| bool draw_selection_here = (draw_selection && i >= selleft && i < selright); | ||
| bool draw_selection_here = (draw_selection && i >= selleft && i <= selright); |
There was a problem hiding this comment.
Fixes selection not drawing on the final column of the sample display (i wonder if this was intentional? there was always 1px unselected even when you select all)
arm9/source/tobkit/sampledisplay.cpp
Outdated
| } | ||
| if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) | ||
| { | ||
| oamSetXY(&oamSub, 16, loop_start_pos-4, DRAW_HEIGHT+18); |
There was a problem hiding this comment.
todo just directly update oamMemory since we are only changing the x pos
see: NitrousTracker/libntxm#34
Draws a sample cursor over the sample display whenever a note should be playing.
I haven't tried drawing with a sprite instead yet so I'm just leaving what I have so far and I'll update this pr
some notes:
i added an overlay widget show/hide callback to
GUI, so we can avoid drawing the cursor when a messagebox appears over it (otherwise the sample display overlaps the messagebox). specifically this also allows us to erase cursors just before the messagebox draws (so we don't just see cursors frozen in time). This could also be used to solve #150 perhaps. Drawing with sprites instead would probably make this easier.the sample display also has been changed to use a drawing request system, instead of direct calls to
draw, as otherwise conflicting draws may happen during the same frame (e.g. making a selection whilst a cursor is moving). The sample display isn't continuously drawn if the song is stopped, only if it's showing cursors. Again using sprites would probably solve this issue (i did it in the way i did so the cursor could draw under the sampledisplay zoom buttons/loop handles but perhaps it isn't that big of a deal if it overlaps them)the function
calcCursoris quite verbose looking but covers various edge cases: the cursor reversing from a ping pong loop where the step size would put it past the end of the sample, a cursor within a loop region smaller than the step size itself, etc. The current implementation here does not have accuracy issues from my testingThe timer handler calls
calcCursordirectly instead of using ticks (i tried the latter but couldn't get it to be nearly as accurate lol), i suppose it is then plausible that under extremely high load the cursor will lag behind. I have tested this with an extremely performance intensive xm i made (16 channels, 255 bpm, 0 tmp, playing notes and calculating effects in every cell) and it doesn't seem to cause cursor drift issues, but worth notingMore notes are in review comments
Additionally if you like here are two xm files I made for testing cursor drift: the first one is a single sine wave sample of around 5s with two visible and audible blips, and the sample pingpong loops basically indefinitely (i.e. load the xm, press play, open the sample display, and see if the audible blips occur at the same time as the cursor passing over them). For me testing this drift didn't become noticeable until around 5 minutes.
https://github.com/prayerie/nitrictracker/raw/refs/heads/main/cursor_test_1.xm
The second test file is similar but it plays multiple notes simultaneously at different notes using forward instead of pingpong loop:
https://github.com/prayerie/nitrictracker/raw/refs/heads/main/cursor_test_2.xm