Skip to content

Allow communication of currently playing sample info from Player to arm9 #44

Open
prayerie wants to merge 3 commits into
NitrousTracker:0.6.xfrom
prayerie:playpos_stuff
Open

Allow communication of currently playing sample info from Player to arm9 #44
prayerie wants to merge 3 commits into
NitrousTracker:0.6.xfrom
prayerie:playpos_stuff

Conversation

@prayerie

@prayerie prayerie commented May 26, 2026

Copy link
Copy Markdown

note, I wrote most of this code a while ago, so if it looks a bit dodgy in how it's done etc that's ok ofc just please lemme know :o)

This adds a new struct PlayingSampleInfo:

typedef struct
{
	u64 playbackpos;	
	u32 playbackfreq;			
	u8 active;
	u8 looprev;
	u8 instidx;						
	u8 smpidx;
} PlayingSampleInfo;

It's arranged to have minimal padding.

Player allows for setting a pointer to an array of 16 of these (one per channel) to facilitate communication between arm9 and arm7 about which samples are currently playing, and at what frequency (doing it this way is preferred to avoid FIFO message spam).

This addition is designed with the sample playhead cursor in mind, but in order to keep the fork of libntxm (somewhat) uncoupled from NitrousTracker, the names don't reference sample cursors, as in theory it could be used for something else..

A FIFO command is added to set the location of this array of structs from arm9 code.

Also, bendNote and bendNoteDirect in Sample and Instrument have been updated to return the frequency bent to, which allows "playbackfreq" to remain accurate with portamento, arpeggio, etc commands

Comment thread libntxm/arm7/source/player.cpp Outdated
@prayerie prayerie changed the title Allow communicating of currently playing sample info from Player to arm9 Allow communication of currently playing sample info from Player to arm9 May 26, 2026
@exelotl

exelotl commented May 31, 2026

Copy link
Copy Markdown
Collaborator

I had a look at this - it seems quite risky to me, as it's entirely possible that the ARM9 could read from the PlayingSampleInfo array while the ARM7 is in the middle of writing it.

Though I believe it could be safe as long as:

  1. The data passed into setPlayingSampleInfoPtr is aligned to 32 bytes and is a multiple of 32 bytes in size (so that nothing else occupies the same cache line).
  2. The data on the ARM9 side is only accessed via an uncached mirror.
  3. The ARM9 code can cope with the PlayingSampleInfo struct being in a partially written state. (if not then I suppose a lock will be needed).

The presence of a 64-bit field also concerns me as I would assume only 32-bit writes are atomic, but I could easily be wrong here x)

In any case, I think I'll need to see the NT half of this code before I can conclude whether it's OK or not 😅

@prayerie

Copy link
Copy Markdown
Author

I had a look at this - it seems quite risky to me, as it's entirely possible that the ARM9 could read from the PlayingSampleInfo array while the ARM7 is in the middle of writing it.

Though I believe it could be safe as long as:

  1. The data passed into setPlayingSampleInfoPtr is aligned to 32 bytes and is a multiple of 32 bytes in size (so that nothing else occupies the same cache line).

  2. The data on the ARM9 side is only accessed via an uncached mirror.

  3. The ARM9 code can cope with the PlayingSampleInfo struct being in a partially written state. (if not then I suppose a lock will be needed).

The presence of a 64-bit field also concerns me as I would assume only 32-bit writes are atomic, but I could easily be wrong here x)

In any case, I think I'll need to see the NT half of this code before I can conclude whether it's OK or not 😅

that makes sense yes :-) the NT part of the code does indeed use an uncached mirror. I'll reply properly more when i'm home

@prayerie

prayerie commented Jun 1, 2026

Copy link
Copy Markdown
Author

Forgot to reply yesterday, but I'll put this here v quickly and update/put the nt code in a pr later on

  1. i'm not sure if you mean literally the value of the pointer itself or the array it points to; as for the latter, it is 16 * 16 bytes, aligning each struct in the array to 32 bytes will double the memory it requires to 512 bytes (edit: ofc doesn't apply if you only meant the start of the array, rather than all the individual members), but that's presumably ok. (if using a 32 bit value for playbackpos instead, the struct will become 12 bytes in size, but either way once aligned it will effectively be padded to 32 anyway).
  2. mentioned above (the nt code for this already uses memUncached)
  3. this is valid and i have not accounted for this, however i have used the sample cursor for a long time including on very intensive imported songs etc and it has never presented an issue/seems to jump around. if this does happen and does cause inaccuracy, it would only be ephemeral and correct itself, rather than cascading

re the 64 bit field: i didn't notice any slowdowns whatsoever, however it has been a while since i initially tested it out using just a 32 bit value for the sample's position, so i'll see if the accuracy even matters to that degree, maybe it is just fine as a u32

@asiekierka asiekierka left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aligning the array of structs should be enough to ensure no cache line conflicts.

Comment thread libntxm/common/source/sample.cpp Outdated
CommandDbgOut("finestep: 0x%x channel: 0x%x\n", fine_step, channel);
SCHANNEL_TIMER(channel) = SOUND_FREQ((int)GET_FREQ_DIRECT(fine_step));
u32 bendfreq = GET_FREQ_DIRECT(fine_step);
SCHANNEL_TIMER(channel) = SOUND_FREQ((int)bendfreq);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#define SOUNDXTMR_FREQ(n)            TIMER_FREQ_SHIFT(n, 1, 1)

SOUND_FREQ is an inaccurate rounding of a Hz-based frequency. As such, I think it is unwise to use the Hz-based value as a return value - it can lead to difficult-to-debug inaccuracies in the sample cursor on some playback rates.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noted, I'll change this, thanks

Comment thread libntxm/arm7/source/player.cpp Outdated
@prayerie

prayerie commented Jun 2, 2026

Copy link
Copy Markdown
Author

fwiw re exelotl's point, i changed the playback position to be 32 bit and noticed no accuracy loss over time, so i changed that also

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants