Log In  


Cart #20797 | 2016-05-18 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
6



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.

6


Awesome! That could be very useful. I haven't seen stat() used like that before, is there documentation somewhere for the parameters you're using?


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]