This cart is basically a demonstration of a simple tool/function I've made to check/debug the music playing in one of my project, the function need no external dependency and should not clobber your variables as all of them are declared as local. You only need to call the function with the Y position as parameter (positive number are relative to the top of the screen, negative from the bottom) in your update screen function to display a bar with the current status of music playing.

There are four zone, one for each channel, the green/red bubble indicate is the channel is playing or not (green == playing, red, not playing) the number next to the bubble is the pattern used on that channel, and the bar on the bottom is the current position in the pattern.

The function itself:

function debug_music(y) if y < 0 then y = 128 - 17 + y end rectfill(0, y, 127, y+18, 0) rect(1, y+1, 125, y+16, 7) for c=0,3 do local p = stat(16+c) local b = stat(20+c)*25 / 32 local col = 8 if p > -1 then col = 11 end circfill(9+c*32, 6+y, 2, col) print(p, 15+c*32, 4+y, 7) rectfill(3+c*32, 10+y, 27+c*32, 13+y, 6) if p >= 0 then rectfill(3+c*32, 10+y, 3+b+c*32, 13+y, 3) end end end |

18/05/2016: Version 0.2 - New functionalities, see below

Version 0.2r2: correct a bug on effect calculation

I hope it will be useful to someone :)

I used the demo Woo as a base to demonstrate the function in the demo cart.

it came from exploration with an hint from the latest demo that Zep made (the Jam#2 invitation), but the problem is, the invitation can't be run directly on current version of Pico-8, I had to hack it a bit get correct the version, but he use stat() to synchronise the graphics with music, and he use stat(20) which is the current beat of channel 1.

I've then played a bit with stat to see what that stat(20) was, and discover that there were a few non documented values:

stat(16) to stat(19) are current pattern for channel 1 to 4, and stat(20) to stat(23) are the beat (the position in the measure) of the current pattern.

Both are replying -1 if the channel is not playing, or the pattern number for the first, and the position in the measure (a number from 0 to 31 or 1 to 32 can't remember)

Great discovery, I've been trying to come up with some sort of solution that'd let me make a rhythm game for a while now and this is just what I needed!

Much more convenient than having to rely on a timer syncing up with the music. I was even thinking of suggesting Zep to add some way of retrieving the state of the music player at runtime, but I guess stat() already did that and we just didn't know about it.

What would be nice is to have a way to a way to get direct sync from the music to the game logic.

@zep, if I'm correct, bit 7 in the pattern listing is still unused, so maybe use it as a "trigger" for calling a special function like _musictick for exemple, that could be an idea!

I've added some funny display to the bar, now it display in nearly real time the exact note the channel is playing. There is maybe a delay between tbe not and what is display as the function is not called at the same rate as the music internal clock, so it's not perfect.

There is two different mode for that display, an attempt to display somewhat graphically (mode = 1) (I still need to work on this one) and one which is identical to the tracker view (mode ~= 1)

function debug_music(y,mode) if mode == nil then mode = 0 end if y < 0 then y = 128 - 22 + y end rectfill(0, y, 127, y+24, 0) rect(1, y+1, 125, y+22, 7) for c=0,3 do local p = stat(16+c) local b = stat(20+c)*25 / 32 local col = 8 if p > -1 then col = 11 end circfill(9+c*32, 6+y, 2, col) print(p, 15+c*32, 4+y, 7) rectfill(3+c*32, 10+y, 27+c*32, 13+y, 6) if p >= 0 then rectfill(3+c*32, 10+y, 3+b+c*32, 13+y, 3) end detailchannel(c, 3+c*32, y+15,mode) end end function detailchannel(channel, x, y, mode) local notes={"c ","c#","d ","d#","e ","e#","f ","g ","g#","a ","a#","b "} local volus={1,1,2,2,3,3,4,4} local pattern=stat(16 + channel) local beat=stat(20 + channel) local val1, val2, inst, note, effe, volu, padaddr, beataddr, octave,i,j if (pattern >= 0) then pataddr=0x3200+pattern*68 beataddr=pataddr+2*beat val1=peek(beataddr) val2=peek(beataddr+1) inst=band(val1/64, 0x03) inst=inst+(band(val2,0x01)*4) note=band(val1,0x3f) octave=flr(note/#notes) note=(note%#notes)+1 note=notes[note]..octave effe=band(val2/16,0x07) volu=band(val2/2,0x07) if mode==1 then --volume for i=0,7 do j = 6 if (volu>=i) then j = 3 end line(x+i, y+5, x+i, y+5-volus[i+1], j) end if volu > 0 then --note+inst in color print(note, x+9, y+1, inst+8) --effect if effe > 0 then print(effe, x+22, y+1, 7) end end print(note, x+9, y+1, inst+8) else -- tracker style if volu > 0 then print(note, x, y+1, 7) print(inst, x+13, y+1, 14) print(volu, x+18, y+1, 12) if effe > 0 then print(effe, x+22, y+1, 13) else print(".", x+22, y+1, 2) end else print("...", x, y+1, 2) print(".", x+13, y+1, 2) print(".", x+18, y+1, 2) print(".", x+22, y+1, 2) end end end end |

The code is not the most compact we can, as I made it to be somewhat readable.

I hope people will find this version interesting :)

Edit: I think I overlooked the effect calculation and there is a bug, I will correct it soon

Edit2: Yep found, I will update the carts.. :D

[Please log in to post a comment]