The first script I propose is just a mere reusage of the C code in quickbms with just some minimal changes for returning header_offset and start_offset other than subsong_offset.
Code:
set MEMORY_FILE10 string "
typedef unsigned int off_t;
typedef unsigned int size_t;
int function(unsigned char *sh, int target_subsong, int *header_offset, int *start_offset) {
int i;
off_t subsong_offset = 0;
int total_subsongs = *(int*)(0x00+sh);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) return -1;
for (i = 0; i < total_subsongs; i++) {
off_t offset = 0x40 + 0x40 * i;
size_t subsong_size = *(unsigned int *)(offset + 0x08+sh) * *(unsigned int *)(offset + 0x10+sh) * *(unsigned int *)(offset + 0x14+sh);
if (i + 1== target_subsong) {
*header_offset = offset;
*start_offset = subsong_offset;
}
subsong_offset += subsong_size;
}
return subsong_offset;
}
"
get SIZE asize
log MEMORY_FILE 0 SIZE
math header_offset = 0
math start_offset = 0
calldll MEMORY_FILE10 function tcc subsong_offset MEMORY_FILE 123 &header_offset &start_offset
print "%subsong_offset% %header_offset% %start_offset%"
This method is the best if you have no time and the code would be too slow in bms script.
The code is very simple so it's also possible to make a native bms script, give me some minutes.