A new version for you. Slightly improved note movement to give a better feel of a beat as well as some simple sound this time.
// ------------
// DECLARATIONS
// ------------
// Declare constants
// --Beats
#constant BEAT_LEFT %0001
#constant BEAT_UP %0010
#constant BEAT_RIGHT %0100
// ---Booleans values
#constant TRUE 1
#constant FALSE 0
// ---Media control
#constant MEDIACONTROL_DLL_LIMIT 8
// ---Notes
#constant A5 = 880.00
#constant Bb5 = 932.33
#constant B5 = 987.77
#constant C6 = 1046.50
#constant Db6 = 1108.73
#constant D6 = 1174.66
#constant Eb6 = 1244.51
#constant E6 = 1318.51
#constant F6 = 1396.91
#constant Gb6 = 1479.98
#constant G6 = 1567.98
// User defined types
// ---Media control
type type_mediaControl
nextDLL as integer
endType
// ---Songs
type type_song
barFlashLife as integer
beatCount as integer
beatFlashLife as integer
beatsPerMinute as integer
beatsPerSecond as float
currentBar as integer
currentBeat as integer
currentNote as integer
isStarted as boolean
length as integer
millisecondsPerBeat as float
millisecondsPlayed as dWord
startTime as dWord
endType
// ---Timer system
type type_timerSystem
current as dWord
isRenderFrame as boolean
ticksPassed as dWord
perfTimerIncrement as dWord
sinceLastRenderFrame as dWord
ratio as float
endType
// ----------------
// MAIN ENTRY POINT
// ----------------
// Set up display
global SCREEN_WIDTH as integer : SCREEN_WIDTH = desktop width()
global SCREEN_HEIGHT as integer : SCREEN_HEIGHT = desktop height()
set display mode SCREEN_WIDTH, SCREEN_HEIGHT, 32
set window title "Rythm Game Help"
// Preven escape key from automatically exiting
disable escapeKey
// Hide loading
sync on
sync rate 0
sync
center text SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, "LOADING..."
sync
// Initialise the media control system
mediaControl_init()
// Initialise and start the timer system
timerSystem_init()
timerSystem_start()
// Setup song details (for a song that is 1 minute 20 seconds long and is 160bpm)
song_setup("1:20", 160)
// Enable the 3D backdrop
backdrop on
color backdrop 0x212121
// Start the main loop
local breakLoop as boolean : breakLoop = FALSE
while (breakLoop = FALSE)
// Update the timer system
timerSystem_update()
// If escape is pressed then break the loop
if (keyState(1) = TRUE)
breakLoop = TRUE
endIf
// If enter is pressed then start the song
if (keyState(28) = TRUE)
if (song.isStarted = FALSE)
song_start()
endIf
endIf
// Update the screen at approximately 60 frames per second
if (timerSystem.isRenderFrame)
// Update the song
song_update()
// Render
sync
endIf
endWhile
// Clean up
timerSystem_cleanUp()
// Exit the application
end
// ---------
// FUNCTIONS
// ---------
// Method to find an available DLL Id
function mediaControl_findFreeDLL()
// Local variables
local result as integer : result = 0
local i as integer : i = 0
// Loop through DLLs until a spare ID is found
while (dll exist(mediaControl.nextDLL) = TRUE and i <= MEDIACONTROL_DLL_LIMIT)
inc mediaControl.nextDLL
if (mediaControl.nextDLL > MEDIACONTROL_DLL_LIMIT)
mediaControl.nextDLL = 1
endIf
inc i
endWhile
// If an ID was found, then return it
if (i <= MEDIACONTROL_DLL_LIMIT)
result = mediaControl.nextDLL
else
exit prompt "mediaControl > mediaControl_findFreeDLL: Could not find a free DLL.", "Error"
end
endIf
// End the function
endfunction result
// Method to initialise media control
function mediaControl_init()
// Create an instanct of the media control structure
global mediaControl as type_mediaControl
// Set initial values for next IDs
mediaControl.nextDLL = 1
// End the function
endFunction
// Method to setup a song
function song_setup(_length as string, _beatsPerMinute as integer)
// Declare the song instance
global song as type_song
// Split the length into minutes and seconds
local colonIndex as integer : colonIndex = find first char$(_length, ":")
if (colonIndex = -1)
song.length = val(_length)
else
song.length = val(left$(_length, colonIndex - 1)) * 60 + val(right$(_length, len(_length) - (colonIndex)))
endIf
// Set beat frequency
song.beatsPerMinute = _beatsPerMinute
song.beatsPerSecond = _beatsPerMinute / 60.0
song.millisecondsPerBeat = 1000.0 / (_beatsPerMinute / 60.0)
// Set total beats
song.beatCount = song.beatsPerSecond * song.length
// Create an array of beats
global dim song_beats(song.beatCount - 1) as integer
global beatDelay = 16
local beat as integer
for beat = 0 to (song.beatCount - 1)
local thisBeat as integer : thisBeat = 0
if (beat >= beatDelay)
if (rnd(4) = 1)
inc thisBeat, BEAT_LEFT
endIf
if (rnd(4) = 1)
inc thisBeat, BEAT_UP
endIf
if (rnd(4) = 1)
inc thisBeat, BEAT_RIGHT
endIf
endIf
song_beats(beat) = thisBeat
next beat
// Set the song as not started
song.beatFlashLife = 0
song.currentBar = -1
song.currentBeat = -1
song.isStarted = FALSE
// Set up an array of notes
song.currentNote = 0
global dim song_notes(15) as integer
song_notes(0) = createsound("sound effect", 1, D6 * 2, 2000, 200, 0.02, 0.1, 0.60, 3, 0.64, 5, 10)
song_notes(1) = 0
song_notes(2) = 1
song_notes(3) = createsound("sound effect", 2, F6 * 2, 2000, 200, 0.02, 0.1, 0.60, 3, 0.64, 5, 10)
song_notes(4) = createsound("sound effect", 3, G6 * 2, 2000, 200, 0.02, 0.1, 0.60, 3, 0.64, 5, 10)
song_notes(5) = 2
song_notes(6) = 1
song_notes(7) = createsound("sound effect", 4, Db6 * 2, 2000, 200, 0.02, 0.1, 0.60, 3, 0.64, 5, 10)
song_notes(8) = createsound("sound effect", 5, C6 * 2, 2000, 200, 0.02, 0.1, 0.60, 3, 0.64, 5, 10)
song_notes(9) = 0
song_notes(10) = 5
song_notes(11) = createsound("sound effect", 6, A5 * 2, 2000, 200, 0.02, 0.1, 0.60, 3, 0.64, 5, 10)
song_notes(12) = 6
song_notes(13) = 5
song_notes(14) = 4
song_notes(15) = 6
// End the function
endFunction
// Method to start the song
function song_start()
// Set the song as started
song.isStarted = TRUE
song.startTime = timer()
// End the function
endFunction
// Method to update the song
function song_update()
// Check the song is started
if (song.isStarted = TRUE)
// Calculate beat/bar flash alpha
local beatFlashRatio as float : beatFlashRatio = (song.beatFlashLife / 100.0)
local barFlashRatio as float : barFlashRatio = (song.barFlashLife / 100.0)
// Variables representing beat rendering
local beatSize as integer : beatSize = 64
local beatSpacing as integer : beatSpacing = 16
local beatStartY as integer : beatStartY = -beatSize
local beatTargetY as integer : beatTargetY = SCREEN_HEIGHT - beatSpacing
local millisecondToPixel as float : millisecondToPixel = beatSize / song.millisecondsPerBeat
local totalWidth as integer : totalWidth = (beatSize * 3) + (beatSpacing * 2)
// Loop through and render beats
local offsetRatio as float : offsetRatio = 1.0 - sin(((song.millisecondsPerBeat - (song.millisecondsPlayed mod song.millisecondsPerBeat)) / song.millisecondsPerBeat) * 90.0)
local beatPixelOffset as integer : beatPixelOffset = beatSize - (offsetRatio * offsetRatio * beatSize)
local thisBeat as integer : thisBeat = song.currentBeat
local borderColor as dWord : borderColor = createARGB(255, beatFlashRatio * 255.0, 255, beatFlashRatio * 255.0)
local backgroundColor as dWord : backgroundColor = createARGB(128, beatFlashRatio * 255.0, 255, beatFlashRatio * 255.0)
while (thisBeat > -1 and thisBeat <= array count(song_beats()))
// Set co-ordinates
local x1 as integer : x1 = (SCREEN_WIDTH - totalWidth) / 2
local y1 as integer : y1 = beatTargetY - beatPixelOffset - (millisecondToPixel * (thisBeat - song.currentBeat) * song.millisecondsPerBeat)
local x2 as integer : x2 = x1 + beatSize
local y2 as integer: y2 = y1 + beatSize
// Left
if (song_beats(thisBeat) && BEAT_LEFT)
box x1, y1, x1 + 1, y2, borderColor, borderColor, borderColor, borderColor
box x2 - 1, y1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1, y1, x2, y1 + 1, borderColor, borderColor, borderColor, borderColor
box x1, y2 - 1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1 + 1, y1 + 1, x2 - 1, y2 -1, backgroundColor, backgroundColor, backgroundColor, backgroundColor
endIf
// Up
inc x1, beatSize + beatSpacing
inc x2, beatSize + beatSpacing
if (song_beats(thisBeat) && BEAT_UP)
box x1, y1, x1 + 1, y2, borderColor, borderColor, borderColor, borderColor
box x2 - 1, y1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1, y1, x2, y1 + 1, borderColor, borderColor, borderColor, borderColor
box x1, y2 - 1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1 + 1, y1 + 1, x2 - 1, y2 -1, backgroundColor, backgroundColor, backgroundColor, backgroundColor
endIf
// Right
inc x1, beatSize + beatSpacing
inc x2, beatSize + beatSpacing
if (song_beats(thisBeat) && BEAT_RIGHT)
box x1, y1, x1 + 1, y2, borderColor, borderColor, borderColor, borderColor
box x2 - 1, y1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1, y1, x2, y1 + 1, borderColor, borderColor, borderColor, borderColor
box x1, y2 - 1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1 + 1, y1 + 1, x2 - 1, y2 -1, backgroundColor, backgroundColor, backgroundColor, backgroundColor
endIf
// Change colour for non-current beats
local colorRatio as float : colorRatio = (1.0 * y1 - beatStartY) / (1.0 * beatTargetY - beatStartY)
borderColor = createARGB(255, (1.0 - colorRatio) * 255.0, colorRatio * 255.0, 0)
backgroundColor = createARGB(128, (1.0 - colorRatio) * 255.0, colorRatio * 255.0, 0)
// Next beat
inc thisBeat
if (thisBeat - song.currentBeat > ceil(SCREEN_HEIGHT / (beatSize * millisecondToPixel)))
exit
endIf
endWhile
// Render background bar flash
if (song.barFlashLife > 0)
local backgroundColor as dWord : backgroundColor = createARGB(barFlashRatio * 24.0, 255, 255, 255)
box 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, backgroundColor, backgroundColor, backgroundColor, backgroundColor
endIf
// Render beat keys
// ---Make colours
local borderColor as dWord : borderColor = createARGB(64 + (beatFlashRatio * 191.0), 255, 255, 255)
local backgroundColor as dWord : backgroundColor = createARGB(beatFlashRatio * 64.0, 255, 255, 255)
// ---Co-ordinates
local x1 as integer : x1 = (SCREEN_WIDTH - totalWidth) / 2
local y1 as integer : y1 = SCREEN_HEIGHT - beatSpacing - beatSize
local x2 as integer : x2 = x1 + beatSize
local y2 as integer: y2 = y1 + beatSize
// ---Left
box x1, y1, x1 + 1, y2, borderColor, borderColor, borderColor, borderColor
box x2 - 1, y1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1, y1, x2, y1 + 1, borderColor, borderColor, borderColor, borderColor
box x1, y2 - 1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1 + 1, y1 + 1, x2 - 1, y2 -1, backgroundColor, backgroundColor, backgroundColor, backgroundColor
// ---Up
inc x1, beatSize + beatSpacing
inc x2, beatSize + beatSpacing
box x1, y1, x1 + 1, y2, borderColor, borderColor, borderColor, borderColor
box x2 - 1, y1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1, y1, x2, y1 + 1, borderColor, borderColor, borderColor, borderColor
box x1, y2 - 1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1 + 1, y1 + 1, x2 - 1, y2 -1, backgroundColor, backgroundColor, backgroundColor, backgroundColor
// ---Right
inc x1, beatSize + beatSpacing
inc x2, beatSize + beatSpacing
box x1, y1, x1 + 1, y2, borderColor, borderColor, borderColor, borderColor
box x2 - 1, y1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1, y1, x2, y1 + 1, borderColor, borderColor, borderColor, borderColor
box x1, y2 - 1, x2, y2, borderColor, borderColor, borderColor, borderColor
box x1 + 1, y1 + 1, x2 - 1, y2 -1, backgroundColor, backgroundColor, backgroundColor, backgroundColor
// Decrement beat/bar flash life so it dies in time with the next beat
dec song.beatFlashLife, 100.0 / (song.millisecondsPerBeat / (1000.0 / 60.0))
dec song.barFlashLife, 100.0 / (song.millisecondsPerBeat / (1000.0 / 60.0))
// Update how long the song has been playing for
song.millisecondsPlayed = timer() - song.startTime
// Workout the current beat/bar as a result
local currentBeat as integer : currentBeat = song.millisecondsPlayed / song.millisecondsPerBeat
local currentBar as integer : currentBar = floor((song.millisecondsPlayed / song.millisecondsPerBeat) / 4.0)
// Handle a new beat/bar
if (currentBeat > song.currentBeat)
song.currentBeat = currentBeat
song.beatFlashLife = 100
if (song_notes(song.currentNote) > 0)
play sound song_notes(song.currentNote)
endIf
inc song.currentNote
if (song.currentNote > array count(song_notes()))
song.currentNote = 0
endIf
endIf
if (currentBar > song.currentBar)
song.currentBar = currentBar
song.barFlashLife = 100
endIf
endIf
// End the function
endFunction
// Method to cleanup after the timer system
function timerSystem_cleanUp()
// Clean up arrays
unDim timerSystem_frame()
// End the function
endFunction
// Method to initialise the timer system
function timerSystem_init()
// Create an instance of the timer system structure
global timerSystem as type_timerSystem
// Create an array to hold timer data for the last 30 frames
global dim timerSystem_frame(30) as dWord
endFunction
// Method to start the timer system
function timerSystem_start()
// Find the perftimer increment value
local dll_kernel32 as integer : dll_kernel32 = mediaControl_findFreeDLL()
load dll "kernel32.dll", dll_kernel32
local DLLReturn as dWord : DLLReturn = make memory(4)
call dll dll_kernel32, "QueryPerformanceFrequency", DLLReturn
delete dll dll_kernel32
timerSystem.perfTimerIncrement = *DLLReturn
delete memory DLLReturn
// Grab the initial values
for f = 0 to array count(timerSystem_frame())
timerSystem_frame(f) = timerSystem.perfTimerIncrement / 60.0
next f
timerSystem.current = perftimer()
timerSystem.ticksPassed = timerSystem.perfTimerIncrement / 60.0
timerSystem.ratio = timerSystem.ticksPassed / (timerSystem.perfTimerIncrement / 60.0)
// Force the first update to be a render frame
timerSystem.sinceLastRenderFrame = 9999
// End the function
endFunction
// Method to update the timer system
function timerSystem_update()
// Default to a non-render frame
timerSystem.isRenderFrame = FALSE
// Update the timer values
local average as float : average = 0
local f as integer
for f = 0 to (array count(timerSystem_frame()) - 1)
timerSystem_frame(f) = timerSystem_frame(f + 1)
inc average, timerSystem_frame(f + 1)
next f
local tTimer as dWord : tTimer = perftimer()
timerSystem_frame(array count(timerSystem_frame())) = tTimer - timerSystem.current
inc timerSystem.sinceLastRenderFrame, tTimer - timerSystem.current
timerSystem.current = tTimer
inc average, timerSystem_frame(array count(timerSystem_frame()))
average = average / (array count(timerSystem_frame()) + 1)
timerSystem.ticksPassed = average
timerSystem.ratio = timerSystem.ticksPassed / (timerSystem.perfTimerIncrement / 60.0)
// Check if this is a render frame
if (timerSystem.sinceLastRenderFrame > (timerSystem.perfTimerIncrement / 60.0))
timerSystem.isRenderFrame = TRUE
timerSystem.sinceLastRenderFrame = 0
endIf
// End the function
endFunction
// Method to produce an ARGB colour value
function createARGB(_alpha as integer, _red as integer, _green as integer, _blue as integer)
// Produce the colour value
local color as dWord
color = (_alpha << 24) || (_red << 16) || (_green << 8) || (_blue)
// End the function
endFunction color
// ------------------
// BORROWED FUNCTIONS
// ------------------
// This method was made by Ric and was posted here: http://forum.thegamecreators.com/?m=forum_view&b=6&t=49008&p=0
function createsound(name$,soundnumber,frequency#,length#,loudness#,bend#,decay#,vibratospeed#,vibratodepth#,tremelospeed#,tremelodepth#,attack#)
outWord as word
dword1 as dword: dword2 as dword: dword3 as dword: dword4 as dword
dword5 as dword: dword6 as dword: dword7 as dword
samples=int((length#/1000)*44100)
if memblock exist(1) then delete memblock 1
make memblock 1,samples*2+28
` write 28 memblock header bytes
dword1=1 ` gg query: is this the number of channels?
dword2=2 ` gg query: is this the number of bytes per sample?
dword3=22050 ` gg query: seems to be half the number of samples per second - why?
dword4=88200 ` gg query: is this the number of bytes per second?
dword5=4 ` gg query: what does this represent?
dword6=16 ` gg query: (ditto) ?
dword7=0 ` gg query: (ditto) ?
position=0
write memblock dword 1, position, dword1 : inc position,4
write memblock dword 1, position, dword2 : inc position,4
write memblock dword 1, position, dword3 : inc position,4
write memblock dword 1, position, dword4 : inc position,4
write memblock dword 1, position, dword5 : inc position,4
write memblock dword 1, position, dword6 : inc position,4
write memblock dword 1, position, dword7 : inc position,4
rem generate and write wave
riseinloudness#=loudness#
for x=1 to samples
outInteger=int(sin((x/122.5)*(frequency#+vibratodepth#*sin(theta#)))*(loudness#-fallinloudness#-riseinloudness#+tremelodepth#*sin(phi#)))*3.0
if outInteger <-32767 then outInteger=-32767 ` gg query: is this the valid range?
if outInteger>32767 then outInteger=32767 ` gg query: (ditto) ?
outWord=outInteger
inc theta#,vibratospeed#
inc phi#,tremelospeed#
dec frequency#,bend#
if fallinloudness#<loudness#
inc fallinloudness#,decay#
endif
if riseinloudness#>0
dec riseinloudness#,attack#
endif
write memblock word 1, position, outWord : inc position,2
next x
if sound exist(soundnumber)=1 then delete sound soundnumber
make sound from memblock 999, 1 ` assumes you won't need sound number 999!
clone sound soundnumber, 999
delete sound 999
` memblock no longer required
delete memblock 1
endfunction soundnumber
[Edit]Missed an 'n' in versio[n] and couldn't let it go.

[/Edit]

Previously TEH_CODERER.