65816 software sprite rotation algorithm

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
65816 software sprite rotation algorithm
by on (#69005)
Code:
!add = "clc : adc"
!sub = "sec : sbc"


sep #$20
lda #$88
sta $2115
lda !bank
pha
plb


rep #$30

lda !angle
asl
and #$01fe
tax
lda sine_table+$000000,x
sta !sine
txa
!add #$0080
and #$01fe
tax
lda sine_table+$000000,x
sta !cosine

lda !sine
!add !cosine
asl #2
sta !x_displacement

lda !cosine
!sub !sine
asl #2
sta !y_displacement

lda !width
tay
asl #2
xab
!add !x_pixel
find_x_pixel:
sub !x_displacement
dey
bne find_x_pixel
sta !x_pixel

lda !width
tay
asl #2
xab
!add !y_pixel
find_y_pixel:
sub !y_displacement
dey
bne find_y_pixel
sta !y_pixel


render_sprite:
lda !x_pixel
pha
lda !y_pixel
pha
lda !width
pha
lda !destination
sta $2116
render_line:
jsr make_affine_plane
dec !width
bne render_line
rep #$20
pla
sta !width
pla
!add !cosine
sta !y_pixel
pla
!add !sine
sta !x_pixel
lda !destination
!add #$0020
sta !destination
dec !height
bne render_sprite
rts






make_affine_plane:
rep #$30
lda !y_pixel
sta !pixel_address_1
!sub !sine
sta !pixel_address_2
!sub !sine
sta !pixel_address_3
!sub !sine
sta !pixel_address_4
!sub !sine
sta !pixel_address_5
!sub !sine
sta !pixel_address_6
!sub !sine
sta !pixel_address_7
!sub !sine
sta !pixel_address_8
!sub !sine
sta !y_pixel
lda !x_pixel
sta !pixel_address_1-1
!add !cosine
sta !pixel_address_2-1
!add !cosine
sta !pixel_address_3-1
!add !cosine
sta !pixel_address_4-1
!add !cosine
sta !pixel_address_5-1
!add !cosine
sta !pixel_address_6-1
!add !cosine
sta !pixel_address_7-1
!add !cosine
sta !pixel_address_8-1
!add !cosine
sta !x_pixel
sep #$20
lda (!pixel_address_1)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_2)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_3)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_4)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_5)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_6)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_7)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_8)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !bit_plane_1
stx $2118
ldx !bit_plane_2
stx $2118
rts




sine_table:
dw 0,6,13,19,25,31,38,44,50,56,62,68,74,80,86,92
dw 98,104,109,115,121,126,132,137,142,147,152,157,162,167,172,177
dw 181,185,190,194,198,202,206,209,213,216,220,223,226,229,231,234
dw 237,239,241,243,245,247,248,250,251,252,253,254,255,255,256,256
dw 256,256,256,255,255,254,253,252,251,250,248,247,245,243,241,239
dw 237,234,231,229,226,223,220,216,213,209,206,202,198,194,190,185
dw 181,177,172,167,162,157,152,147,142,137,132,126,121,115,109,104
dw 98,92,86,80,74,68,62,56,50,44,38,31,25,19,13
dw 0,-6,-13,-19,-25,-31,-38,-44,-50,-56,-62,-68,-74,-80,-86,-92
dw -98,-104,-109,-115,-121,-126,-132,-137,-142,-147,-152,-157,-162,-167,-172
dw -177,-181,-185,-190,-194,-198,-202,-206,-209,-213,-216,-220,-223,-226,-229,-231
dw -234,-237,-239,-241,-243,-245,-247,-248,-250,-251,-252,-253,-254,-255,-255,-256
dw -256,-256,-256,-256,-255,-255,-254,-253,-252,-251,-250,-248,-247,-245,-243,-241
dw -239,-237,-234,-231,-229,-226,-223,-220,-216,-213,-209,-206,-202,-198,-194,-190
dw -185,-181,-177,-172,-167,-162,-157,-152,-147,-142,-137,-132,-126,-121,-115,-109
dw -104,-98,-92,-86,-80,-74,-68,-62,-56,-50,-44,-38,-31,-25,-19,-13,-6


I haven't tested this out yet, but I was too excited not to post it. This is can be used during load times between levels. This uses the PPU for the purpose of memory organization since I wanted to avoid sloppy 65816 code. This wouldn't work during active display for said reason, but thanks to 128 kB of work ram, you don't need to.

Something I like about storing rotated sprites in work ram is they can take less memory than most people think. Angles 180-360 degrees are equivelant to 0-180 degrees with vertical and horizontal flipping applied. You can further minimize the amount of availeable memory by making use of symetrical sprites so that angles 0-90 become mirror images of angles 90-180.

by on (#69006)
So that people don't compare your game to Midnight Club or WWE for PSP, how many tiles of rotation can be created per second of blank-screen load time?

by on (#69007)
tepples wrote:
So that people don't compare your game to Midnight Club or WWE for PSP, how many tiles of rotation can be created per second of blank-screen load time?


approxmately 180 16x16 sprites per second

by on (#69009)
This sounds pretty good to me. You're right that 128k of WRAM is a lot and that it can be put to good use that way. Rotating sprites during gameplay could look good in a SNES game.

(too bad this wouldn't be applicable on the NES as you only have much less WRAM and less time to update tiles dynamically).

What bothers me though is the completely uncommented code. Not only it is recommended to put some comments in your code stricly for personal use, but if you want to share code with other people, then you must comment it.

by on (#69013)
Bregalad wrote:
you must

That could sound bossy. When confronted with a generous donation of library code like this, it's nicer not to give the donor an excuse to take his proverbial ball and go home.

The dw was originally all one line before I split it up so as not to widen the page.

by on (#69020)
Code:
!add = "clc : adc"
!sub = "sec : sbc"


sep #$20
lda #$88
sta $2115         ;; full graphics 4-bit v-ram loading 0aaaaaaabbbccccc -> 0aaaaaaacccccbbb
lda !bank         ;; the bank that holds the 8-bit 256x256 bitmap
pha            ;; of sprite being rotated
plb


rep #$30

lda !angle         ;; find sine and cosine
asl
and #$01fe
tax
lda sine_table+$000000,x
sta !sine
txa
!add #$0080
and #$01fe
tax
lda sine_table+$000000,x
sta !cosine


lda !sine
!add !cosine         ;; find the negative x displacement
asl #2            ;; 4 pixels up left from center
sta !x_displacement

lda !cosine         ;; find the negative y displacement
!sub !sine         ;; 4 pixels up left from center
asl #2
sta !y_displacement

lda !width         ;; add center of sprite to x pixel coordinate
tay
asl #2
xab
!add !x_pixel
find_x_pixel:
sub !x_displacement      ;; subtract (x displacement)*width from x pixel
dey            ;; coordinate
bne find_x_pixel
sta !x_pixel

lda !width         ;; add center of sprite to y pixel coordinate
tay
asl #2
xab
!add !y_pixel
find_y_pixel:         ;; subtract (y displacement)*width from y pixel
sub !y_displacement      ;; coordinate
dey
bne find_y_pixel
sta !y_pixel


render_sprite:         ;; push x and y pixel coordinates
lda !x_pixel         ;; and width onto stack to save
pha            ;; for rendering the line after it
lda !y_pixel
pha
lda !width
pha
lda !destination
sta $2116
render_line:
jsr render_8_pixels
dec !width
bne render_line         ;; repeat rendering 8-pixels "width" times
rep #$20
pla            ;; recover x and y coordinates and width
sta !width         ;; next line of pixels
pla
!add !cosine
sta !y_pixel         ;; find new starting point for y coordinate
pla
!add !sine
sta !x_pixel         ;; find new starting point for x coordinate
lda !destination
!add #$0020
sta !destination      ;; set v-ram address reg at the next line of pixels
dec !height
bne render_sprite
rts






render_8_pixels:
rep #$30
lda !y_pixel
sta !pixel_address_1      ;; unrolled loop for finding y coordinate of 8 pixels
!sub !sine
sta !pixel_address_2
!sub !sine
sta !pixel_address_3
!sub !sine
sta !pixel_address_4
!sub !sine
sta !pixel_address_5
!sub !sine
sta !pixel_address_6
!sub !sine
sta !pixel_address_7
!sub !sine
sta !pixel_address_8
!sub !sine
sta !y_pixel
lda !x_pixel
sta !pixel_address_1-1      ;; unrolled loop for finding x coordinate of 8 pixels
!add !cosine         ;; top byte (whole number) of x coordinate is written over
sta !pixel_address_2-1      ;; bottom byte (decimal) of y coordinate creating
!add !cosine         ;; 16 bit pixel addresses in the form of yyyyyyyyxxxxxxxx
sta !pixel_address_3-1
!add !cosine
sta !pixel_address_4-1
!add !cosine
sta !pixel_address_5-1
!add !cosine
sta !pixel_address_6-1
!add !cosine
sta !pixel_address_7-1
!add !cosine
sta !pixel_address_8-1
!add !cosine
sta !x_pixel
sep #$20
lda (!pixel_address_1)      ;; unrolled loop for fetching pixels and
ror            ;; turning 8-bit packed pixel format into 4-bit planar
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_2)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_3)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_4)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_5)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_6)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_7)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
lda (!pixel_address_8)
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !bit_plane_1
stx $2118         ;; send the 4 bytes to v-ram address port and let the PPU do the rest
ldx !bit_plane_2
stx $2118
rts




sine_table:
dw 0,6,13,19,25,31,38,44,50,56,62,68,74,80,86,92,98,104,109,115,121,126,132,137,142
dw 147,152,157,162,167,172,177,181,185,190,194,198,202,206,209,213,216,220,223,226,229
dw 231,234,237,239,241,243,245,247,248,250,251,252,253,254,255,255,256,256,256,256,256
dw 255,255,254,253,252,251,250,248,247,245,243,241,239,237,234,231,229,226,223,220,216
dw 213,209,206,202,198,194,190,185,181,177,172,167,162,157,152,147,142,137,132,126,121
dw 115,109,104,98,92,86,80,74,68,62,56,50,44,38,31,25,19,13,0,-6,-13,-19,-25,-31,-38
dw -44,-50,-56,-62,-68,-74,-80,-86,-92,-98,-104,-109,-115,-121,-126,-132,-137,-142
dw -147,-152,-157,-162,-167,-172,-177,-181,-185,-190,-194,-198,-202,-206,-209,-213,-216
dw -220,-223,-226,-229,-231,-234,-237,-239,-241,-243,-245,-247,-248,-250,-251,-252,-253
dw -254,-255,-255,-256,-256,-256,-256,-256,-255,-255,-254,-253,-252,-251,-250,-248
dw -247,-245,-243,-241,-239,-237,-234,-231,-229,-226,-223,-220,-216,-213,-209,-206,-202
dw -198,-194,-190,-185,-181,-177,-172,-167,-162,-157,-152,-147,-142,-137,-132,-126,-121
dw -115,-109,-104,-98,-92,-86,-80,-74,-68,-62,-56,-50,-44,-38,-31,-25,-19,-13,-6


Hope this helps.

Quote:
This sounds pretty good to me. You're right that 128k of WRAM is a lot and that it can be put to good use that way. Rotating sprites during gameplay could look good in a SNES game.


Whenever I go from a 2D game on the GBA/DS/Wii to an SNES game, the lack of rotating sprites become very apparant, especially during boss fights. It is that missing 2D element that makes SNES games look bland in comparison to more modern 2D games.

by on (#69026)
psycopathicteen wrote:
Hope this helps.

Thank you.

Quote:
Whenever I go from a 2D game on the GBA/DS/Wii to an SNES game, the lack of rotating sprites become very apparant, especially during boss fights. It is that missing 2D element that makes SNES games look bland in comparison to more modern 2D games.

For a 16-angle rotation, you'd need to generate 8 intermediate steps per sprite cel. VH-flipping would give you all 16 angles, and V-flipping or H-flipping alone would give the flipped versions of same. This corresponds roughly to preloading the GBA's 32 matrices with 16 steps of rotation and 16 steps of flipped rotation. An NES-size (128x128 pixel) sprite sheet has 64 16x16 pixel sprite cels on it, needing 512 intermediate steps. At 128 bytes each, these take 64 KiB, so if your engine is already frugal with work RAM, you still have plenty of room.

I guess the limiting factor would be time: At 180 per second, it takes almost three blank-screen seconds to load them. Can this be interleaved with APU loading? Or in the age of GBA nostalgia and widescreen TV, would it be a good idea to use a 256x160 pixel visible window and forced blanking to free up enough PPU time to generate one rotated cel each frame? If that's not practical, perhaps you could generate them linearly (SMS-style) into work RAM while displaying something, and then load them into VRAM using interleaving mode $88 at run time.

by on (#69064)
Code:
!add = "clc : adc"
!sub = "sec : sbc"
!angle = "$00"
!bank = "$01"
!sine = "$02"
!cosine = "$04"
!x_pixel = "$06"
!y_pixel = "$08"
!x_displacement = "$0a"
!y_displacement = "$0c"
!width = "$0e"
!height = "$10"
!destination = "$12"
!pixel_address = "$20"
!bit_plane_1 = "$40"
!bit_plane_2 = "$41"
!bit_plane_3 = "$42"
!bit_plane_4 = "$43"



sprite_rotation:


sep #$20
lda #$84
sta $2115         ;; full graphics 4-bit v-ram loading 0aaaaaaabbbccccc -> 0aaaaaaacccccbbb
lda !bank         ;; the bank that holds the 8-bit 256x256 bitmap
pha            ;; of sprite being rotated
plb


rep #$30

lda !angle         ;; find sine and cosine
asl
and #$01fe
tax
lda sine_table+$000000,x
sta !sine
txa
!add #$0080
and #$01fe
tax
lda sine_table+$000000,x
sta !cosine


lda !sine
!add !cosine         ;; find the negative x displacement
asl #2            ;; 4 pixels up left from center
sta !x_displacement

lda !cosine         ;; find the negative y displacement
!sub !sine         ;; 4 pixels up left from center
asl #2
sta !y_displacement

lda !width         ;; add center of sprite to x pixel coordinate
tay
asl #2
xba
!add !x_pixel
find_x_pixel:
!sub !x_displacement      ;; subtract (x displacement)*width from x pixel
dey            ;; coordinate
bne find_x_pixel
sta !x_pixel

lda !width         ;; add center of sprite to y pixel coordinate
tay
asl #2
xba
!add !y_pixel
find_y_pixel:         ;; subtract (y displacement)*width from y pixel
!sub !y_displacement      ;; coordinate
dey
bne find_y_pixel
sta !y_pixel


render_sprite:         ;; push x and y pixel coordinates
lda !x_pixel         ;; and width onto stack to save
pha            ;; for rendering the line after it
lda !y_pixel
pha
lda !width
pha
lda !destination
sta $2116
render_line:
jsr render_8_pixels
dec !width
bne render_line         ;; repeat rendering 8-pixels "width" times
rep #$20
pla            ;; recover x and y coordinates and width
sta !width         ;; next line of pixels
pla
!add !cosine
sta !y_pixel         ;; find new starting point for y coordinate
pla
!add !sine
sta !x_pixel         ;; find new starting point for x coordinate
lda !destination
!add #$0020
sta !destination      ;; set v-ram address reg at the next line of pixels
dec !height
bne render_sprite
rts






render_8_pixels:
rep #$30
lda !y_pixel
sta !pixel_address+2      ;; unrolled loop for finding y coordinate of 8 pixels
!sub !sine
sta !pixel_address+6
!sub !sine
sta !pixel_address+10
!sub !sine
sta !pixel_address+14
!sub !sine
sta !pixel_address+18
!sub !sine
sta !pixel_address+22
!sub !sine
sta !pixel_address+26
!sub !sine
sta !pixel_address+30
!sub !sine
sta !y_pixel
lda !x_pixel
sta !pixel_address+1      ;; unrolled loop for finding x coordinate of 8 pixels
!add !cosine         ;; top byte (whole number) of x coordinate is written over
sta !pixel_address+5      ;; bottom byte (decimal) of y coordinate creating
!add !cosine         ;; 16 bit pixel addresses in the form of yyyyyyyyxxxxxxxx
sta !pixel_address+9
!add !cosine
sta !pixel_address+13
!add !cosine
sta !pixel_address+17
!add !cosine
sta !pixel_address+21
!add !cosine
sta !pixel_address+25
!add !cosine
sta !pixel_address+29
!add !cosine
sta !x_pixel
sep #$20
ldx !pixel_address+2      ;; unrolled loop for fetching pixels and
lda $0000,x
ror            ;; turning 8-bit packed pixel format into 4-bit planar
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+6
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+10
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+14
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+18
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+22
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+26
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !pixel_address+30
lda $0000,x
ror
rol !bit_plane_1
ror
rol !bit_plane_2
ror
rol !bit_plane_3
ror
rol !bit_plane_4
ldx !bit_plane_1
stx $2118         ;; send the 4 bytes to v-ram address port and let the PPU do the rest
ldx !bit_plane_3
stx $2118
rts




sine_table:
dw 0,6,13,19,25,31,38,44,50,56,62,68,74,80,86,92,98,104,109,115,121,126,132,137,142
dw 147,152,157,162,167,172,177,181,185,190,194,198,202,206,209,213,216,220,223,226,229
dw 231,234,237,239,241,243,245,247,248,250,251,252,253,254,255,255,256,256,256,256,256
dw 255,255,254,253,252,251,250,248,247,245,243,241,239,237,234,231,229,226,223,220,216
dw 213,209,206,202,198,194,190,185,181,177,172,167,162,157,152,147,142,137,132,126,121
dw 115,109,104,98,92,86,80,74,68,62,56,50,44,38,31,25,19,13,0,-6,-13,-19,-25,-31,-38
dw -44,-50,-56,-62,-68,-74,-80,-86,-92,-98,-104,-109,-115,-121,-126,-132,-137,-142
dw -147,-152,-157,-162,-167,-172,-177,-181,-185,-190,-194,-198,-202,-206,-209,-213,-216
dw -220,-223,-226,-229,-231,-234,-237,-239,-241,-243,-245,-247,-248,-250,-251,-252,-253
dw -254,-255,-255,-256,-256,-256,-256,-256,-255,-255,-254,-253,-252,-251,-250,-248
dw -247,-245,-243,-241,-239,-237,-234,-231,-229,-226,-223,-220,-216,-213,-209,-206,-202
dw -198,-194,-190,-185,-181,-177,-172,-167,-162,-157,-152,-147,-142,-137,-132,-126,-121
dw -115,-109,-104,-98,-92,-86,-80,-74,-68,-62,-56,-50,-44,-38,-31,-25,-19,-13,-6


IT WORKS!!!!! Now all I need to do is make a demo showing this off!

by on (#69098)
Want me to make the music for your demo? ^_^ I can do so via SNESMod.

by on (#69106)
KungFuFurby wrote:
Want me to make the music for your demo? ^_^ I can do so via SNESMod.


Sure. What genres are you good at?

by on (#69147)
I've done multiple different types of genres... futuristic, orchestral (not really on realism, though thankfully I don't use what you'd hear in Quicktime when playing MIDI files... for the most part.), medieval, maybe Western, etc. To prove some of this, I'll show you some example tunes.

Here's one example tune, just for show. Actually, this is a collection of tunes in one IT file. This is Brave Battle Saga's battle, boss & victory themes ported over from the Genesis to one IT file, plus a bonus tune. I can even show you how to play a particular sub-tune, and hack the SPC conversion myself to play the other tunes. No seperating required. I really am curious how this one turns out... never have attempted a multi-tune SPC before converted with SNESMod.

Brave Battle Saga ~ Battle, Boss & Victory Themes + 1 Bonus Tune (IT file)

Here's another example tune. This one shows just how long I can actually make my tune... and fit it into one SPC file. This is very old: it comes from a currently abandoned game called SNES All-Stars. Actually, bazz was the original composer, and I got permission to add on to the original. This one's pre-converted: It takes SNESMod to its limits in size and pattern numbers. I did this coversion with mukunda, the creator of SNESMod, and learned how much it takes to max out the size. About 44,000 length of sample, 64 patterns (some of them 128 rows! There is a 64 pattern limitation on SNESMod), and nearly 12 minutes worth of music just to one loop!

SNES All-Stars: Futuristic Boss (IT file ~ the file name is old, and I now consider it by this name)
SNES All-Stars: Futuristic Boss (SPC file ~ fully tagged by myself)

I can't convert to SPC on my end due to me having a non-Intel Mac, but usually my tunes fit the size limit. If there are any problems, then usually when I listen to the SPC file I can tell. I know there's a slight slowdown from the original IT file on conversion.

I can even do echo, though before I do so I estimate the memory consumption so I know how much possible free space I have. This example tune shows that I've done this successfully before. In this case, a friend of mine that is one of the contributors on SNESMusic.org, nensondubois, did the conversion.

Epic Theme

by on (#69750)
I like your music. I might have a little trouble implementing your music into the demo, simply because I'm not as experienced with the SPC700 as I am with the CPU & PPU side of the SNES.

I might take a while with the demo, because I'm also working on my game at the same time, and I have a lot of school and I've been focusing more on my social life.

Sort've offtopic. I really think the internet as a whole is running out of energy. I look around other websites, and I just can't find anything fresh and new that hasn't been discussed to death. Look at any gaming website and they're all talking about the same old stuff they were talking about 10 years ago. The same games, same questions, same replies. Technical debates (non nesdev) were fun for a while, but once I realized it was all about reading off specs, and comparing the system's power by comparing what was done in games, I got tired of it. We all know stuff like colors, Mhz and we all know about X game using Y effect. It was all about what the system did, but never about the stuff it never did but could've been done on that system.

by on (#69806)
That's OK. I've looked up Skipp and Friend's source code and I have a guess on how to get multi-segmented music to play. First, load the music with this code (make sure you have snesmod included in your .asm file via .include ...):

Code:
ldx   #(insert tune ID)
jsr   spcLoad


After that, here's what starts a tune:

Code:
ldx   #0
jsr   spcPlay


#0 represents starting from order zero. This is just a guess, but to play a different segment, first stop the music (JSR spcStop), then use LDX, but with a nonzero value, and play that tune (JSR spcPlay). Should require no modification to the original SNESMod source code this way.

Oh, and here's a custom music collection just for you in one IT file:

SNES Software Sprite Rotation Demo Collection

The numbers that will access the start of a subtune in the collection are:
0
33
42
51
53
69
76
81

The tempo isn't consistent throughout the tunes, hence the reason why I reveal this now. This might be useful if your composer for your game is wondering if there can be more than one tune in an IT file. ^_^

I would be quite happy to attempt to debug problems on this end, though I'm no SNES programmer. ^_^

by on (#71626)
I ended up debugging the IT file myself after converting them myself since one of the tunes had the wrong tempo (turns out I can't go that high in the tempo in one of the subtunes, so my solution was to half the speed and half the tempo)... note that this is done on a Windows computer, not a Mac, so that to me is a limited time offer. All samples were OK.

I confirmed that the multi-tune IT files do work when converting to SPC files. To extract the other tunes, all I had to do was go to $1B20 in the original SPC file which contains the order list, and modify the first few values to FE. There's a reason why I leave FE just before the next sub-tune: it's mainly for the benefit of being able to do that seperation and determining where the next tune is.

New Source IT File
SPC set