I’m trying to make a sign that has 7 words on it where each of the words turns on as they are sung in the song.
I went though the Into to Pixelblaze Pattern but unfortunately I am still stumped on how I would do this. I am struggling with how I would be able to start the pattern at the exact right time, it seems like all the patterns are on a loop and just start automatically when you click on them.
Would anyone be able to help me out with a code that would do the following?
Press button on computer
Pixels 1-20 turn on at 0ms
Pixels 21-40 turn on at 750ms
Pixels 41-60 turn on at 1500ms
Pixels 61-80 turn on at 2250ms
Pixels 81-100 turn on at 3000ms
Pixels 101-120 turn on at 3750ms
Pixels 121-140 turn on at 4125ms
Pixels 1-140 turn off at 4500ms
Thanks in advance to anyone who could help me out!
I wrote this up for you to get you started - it’s pretty specific to your spec, but I’d eventually like to make a more full-featured Choreography pattern that’s quite flexible for animating patterns to a song.
// Spec:
// Press button on computer
// Pixels 1-20 turn on at 0ms
// Pixels 21-40 turn on at 750ms
// Pixels 41-60 turn on at 1500ms
// Pixels 61-80 turn on at 2250ms
// Pixels 81-100 turn on at 3000ms
// Pixels 101-120 turn on at 3750ms
// Pixels 121-140 turn on at 4125ms
// Pixels 1-140 turn off at 4500ms
// There's no keyboard events, but you can slide this sldier when the
// song restarts.
export function sliderRetrigger(v) { accumMs = 0 }
var numModes = 8 // Includes all active modes and a final halting look
var modeStartAt = array(numModes)
modeStartAt[0] = 0
modeStartAt[1] = 750
modeStartAt[2] = 1500
modeStartAt[3] = 2250
modeStartAt[4] = 3000
modeStartAt[5] = 3750
modeStartAt[6] = 4125
modeStartAt[7] = 4500
var idxRangeEnd = array(numModes)
idxRangeEnd[0] = 20
idxRangeEnd[1] = 40
idxRangeEnd[2] = 60
idxRangeEnd[3] = 80
idxRangeEnd[4] = 100
idxRangeEnd[5] = 120
idxRangeEnd[6] = 140
idxRangeEnd[7] = 0
var accumMs = 0
export function beforeRender(delta) {
accumMs += delta
accumMs > 4500 ? accumMs = 4501 : 0 // Halt
t1 = time(.1)
mode = msToMode(accumMs)
}
export function render(index) {
h = t1 + index/pixelCount
s = 1
v = pixelOn(index, mode)
hsv(h, s, v)
}
// Assumes modeStartAt[i] vaues sorted ascending
// Returns mode index for a given number of milliseconds into a song
function msToMode(ms) {
for (i = 0; i < numModes - 1; i++) {
if (ms >= modeStartAt[i] && ms < modeStartAt[i + 1])
return i
}
return numModes - 1 // Past the last mode's start time, use the last mode
}
function pixelOn(index, modeIdx) {
if (modeIdx == 0) return index < idxRangeEnd[modeIdx]
return index >= idxRangeEnd[modeIdx - 1] && index < idxRangeEnd[modeIdx]
}
Hey Jeff, thanks so much for this! This was exactly what I was looking for. I tried it out and it works perfectly! Thanks a million for taking the time to write this up for me!
Would you be able to alter this code slightly to accommodate a range of pixels for each timing instead of from the end of the previous to the end of the active range? (I think that is how it is working)
The reason ask is because my led strip lights can only be cut every 3rd pixel. So for the case that a word uses 20 pixels I would want the 21st to not be light up.
Example:
var modeStartAt = array(numModes)
modeStartAt[0] = 0
modeStartAt[1] = 750
var idxRangeStart = array(numModes)
idxRangeStart[0] = 0
idxRangeStart[1] = 21
var idxRangeEnd = array(numModes)
idxRangeEnd[0] = 19
idxRangeEnd[1] = 40
Huge thanks for any help you would be able to provide, and I’ll be sure to send a video when it’s done!
Sure - we can switch to a more flexible approach then where we have a separate function for each part of the song. This is the same technique seen in the “Example: Modes and waveforms” pattern.
// There's no keyboard events, but you can slide this sldier when the
// song restarts.
export function sliderRetrigger(v) { accumMs = 0 }
var numModes = 8 // Includes all active modes and a final look
var modes = array(numModes)
modes[0] = (i) => i >= 0 && i < 21
modes[1] = (i) => i >= 21 && i < 42
modes[2] = (i) => i >= 42 && i < 60
modes[3] = (i) => i >= 60 && i < 81
modes[4] = (i) => i >= 81 && i < 102
modes[5] = (i) => i >= 102 && i < 120
modes[6] = (i) => i >= 120 && i < 141
modes[7] = (i) => 0
var modeStartAt = array(numModes)
modeStartAt[0] = 0
modeStartAt[1] = 750
modeStartAt[2] = 1500
modeStartAt[3] = 2250
modeStartAt[4] = 3000
modeStartAt[5] = 3750
modeStartAt[6] = 4125
modeStartAt[7] = 4500
var accumMs = 0
export function beforeRender(delta) {
accumMs += delta
accumMs > 4500 ? accumMs = 4501 : 0 // Halt
t1 = time(.1)
mode = msToMode(accumMs)
}
export function render(index) {
h = t1 + index/pixelCount
s = 1
// Call the current mode function
// which will overwrite globals h, s and/or v
v = modes[mode](index)
hsv(h, s, v)
}
// Assumes modeStartAt[i] vaues sorted ascending
// Returns mode index for a given number of milliseconds into a song
function msToMode(ms) {
for (i = 0; i < numModes - 1; i++) {
if (ms >= modeStartAt[i] && ms < modeStartAt[i + 1])
return i
}
return numModes - 1 // Past the last mode's start time, use the last mode
}