Hi everyone,
I have written a program to control what I am going to call a "haunted room." It's a very basic idea, but I think will be highly effective. Basically I'm going to put a Prop-1 and an MP3 player (currently the dreaded VMusic 2...sorry) in a room. When an unassuming partygoer walks by, on their way to the restroom, for example, the Prop-1 will be triggered by a PIR, and will tell the MP3 player to play a sound of a quiet ghostly whisper. Throughout the night these whispers will become louder and more menacing, and eventually a light in the room will turn itself on and off and flicker, etc (this part is not written yet, but I'm working on it).
My question is how to optimize this code, though. I'm using a BRANCH, thanks to one of Jon's Nuts and Volts articles, which works AWESOME (thanks, Jon!). But I have a feeling that this could be optimized somehow, I'm just not sure how. Any ideas are much appreciated.
Thanks,
Liam
PS: Insane_Intensity is first because once the BRANCH routine is over that's the subroutine that I want it to keep triggering. Not sure if that's relevant or not.
' =========================================================================
'
' File...... Haunted_Room2.BS1
' Purpose...
' Author.... Liam Ferris
' Copyright (c) 2009 Liam Ferris
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... lpferris@gmail.com
' Started... 17 NOV 2009
' Updated... 17 NOV 2009
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================
' -----[ Program Description ]---------------------------------------------
'
' This program is meant to haunt a room in a house by playing quiet whispers
' as unsuspecting victims trigger a PIR as they pass the room. As the night
' goes on, the intensity builds and louder whispers are played. As the
' intensity grows, a light will begin to flicker and the whispers will get
' louder and louder.
' -----[ I/O Definitions ]-------------------------------------------------
SYMBOL RX = 7 ' SETUP = UP, no ULN
SYMBOL TX = 6 ' SETUP = UP, no ULN
SYMBOL Trigger = PIN5 ' SETUP = DN
' -----[ Constants ]-------------------------------------------------------
SYMBOL Baud = T2400 ' Set baud rate for VM2
SYMBOL IsOn = 1 ' for active-high in/out
SYMBOL IsOff = 0
SYMBOL Addr = %11
SYMBOL Hold_Time = 2000
' -----[ Variables ]-------------------------------------------------------
SYMBOL idx = B2
SYMBOL relays = B3
SYMBOL counter = B4
SYMBOL state = B5
SYMBOL timer = W4
SYMBOL lottery = W5
' -----[ Initialization ]--------------------------------------------------
SEROUT 0,Baud, ("VST",13) ' VM2 - stop anything that's playing
SEROUT 0,Baud, ("VSV 0",13) ' VM2 - set volume
' -----[ Program Code ]----------------------------------------------------
Main:
IF Trigger = IsOff THEN Main ' wait for trigger
BRANCH state, (Low_Intensity, Low_Intensity, Low_Intensity, Low_Intensity, Medium_Intensity, Medium_Intensity, Medium_Intensity, Medium_Intensity, High_Intensity, High_Intensity, High_Intensity, High_Intensity, High_Intensity, Insane_Intensity) ' Increase the intensity
Insane_Intensity:
DEBUG "Insane_Intensity",CR
PAUSE 500
SEROUT 0,Baud,("VPF 4.mp3",13) ' Play a file named "3.mp3"
DEBUG "Played 4.mp3",CR
state = state + 1
PAUSE Hold_Time
GOTO Main
Low_Intensity:
DEBUG "Low_Intensity",CR
PAUSE 500
SEROUT 0,Baud,("VPF 1.mp3",13) ' Play a file named "1.mp3"
DEBUG "Played 1.mp3",CR
state = state + 1
PAUSE Hold_Time
GOTO Main
Medium_Intensity:
DEBUG "Medium_Intensity",CR
PAUSE 500
SEROUT 0,Baud,("VPF 2.mp3",13) ' Play a file named "2.mp3"
DEBUG "Played 2.mp3",CR
state = state + 1
PAUSE Hold_Time
GOTO Main
High_Intensity:
DEBUG "High_Intensity",CR
PAUSE 500
SEROUT 0,Baud,("VPF 3.mp3",13) ' Play a file named "2.mp3"
DEBUG "Played 3.mp3",CR
state = state + 1
PAUSE Hold_Time
GOTO Main
END
Sometimes BRANCH isn't the best way -- standard IF-THEN statements will do the trick. And you should ALWAYS debounce an input -- I've included in the code below.
' =========================================================================
'
' File...... Haunted_Room2.BS1
' Purpose...
' Author.... Liam Ferris
' Copyright (c) 2009 Liam Ferris
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... lpferris@gmail.com
' Started... 17 NOV 2009
' Updated... 17 NOV 2009
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================
' -----[ Program Description ]---------------------------------------------
'
' This program is meant to haunt a room in a house by playing quiet whispers
' as unsuspecting victims trigger a PIR as they pass the room. As the night
' goes on, the intensity builds and louder whispers are played. As the
' intensity grows, a light will begin to flicker and the whispers will get
' louder and louder.
' -----[ I/O Definitions ]-------------------------------------------------
SYMBOL RX = 7 ' SETUP = UP, no ULN
SYMBOL TX = 6 ' SETUP = UP, no ULN
SYMBOL Trigger = PIN5 ' ULN is pull-down
' -----[ Constants ]-------------------------------------------------------
SYMBOL Baud = OT2400 ' Set baud rate for VM2
SYMBOL Addr = %11
SYMBOL IsOn = 1 ' for active-high in/out
SYMBOL IsOff = 0
SYMBOL Hold_Time = 2000
' -----[ Variables ]-------------------------------------------------------
SYMBOL idx = B2
SYMBOL relays = B3
SYMBOL counter = B4
SYMBOL state = B5
SYMBOL timer = W4
SYMBOL lottery = W5
' -----[ Initialization ]--------------------------------------------------
Reset:
SEROUT TX, Baud, ("VST", 13) ' VM2 - stop anything that's playing
SEROUT TX, Baud, ("VSV 0", 13) ' VM2 - set volume
' -----[ Program Code ]----------------------------------------------------
Main:
PAUSE Hold_Time
timer = 0 ' reset timer
Check_Trigger:
PAUSE 5 ' loop pad
timer = timer + 5 * Trigger ' update timer
IF timer < 100 THEN Check_Trigger ' wait for 0.1 sec input
Update_State:
state = state + 1
Handle_State:
IF state <= 4 THEN Low_Intensity
IF state <= 8 THEN Medium_Intensity
IF state <= 13 THEN High_Intensity
state = 0
Insane_Intensity:
DEBUG "Insane_Intensity",CR
PAUSE 500
SEROUT TX, Baud, ("VPF 4.mp3", 13) ' Play a file named "4.mp3"
DEBUG "Played 4.mp3",CR
GOTO Main
Low_Intensity:
DEBUG "Low_Intensity",CR
PAUSE 500
SEROUT TX, Baud, ("VPF 1.mp3",13)
DEBUG "Played 1.mp3",CR
GOTO Main
Medium_Intensity:
DEBUG "Medium_Intensity", CR
PAUSE 500
SEROUT TX, Baud, ("VPF 2.mp3", 13)
DEBUG "Played 2.mp3",CR
GOTO Main
High_Intensity:
DEBUG "High_Intensity", CR
PAUSE 500
SEROUT TX, Baud, ("VPF 3.mp3", 13)
DEBUG "Played 3.mp3",CR
GOTO Main
END
OK, that makes more sense. I was stuck in this mess of FOR-NEXT loops that was driving me nuts until I came upon your BRANCH article, but never thought of using IF-THEN. Also thanks for the debounce - I somehow always manage to forget that too. I'll get there one day.
Thanks for the assistance, Jon!
Liam
Another technique you could employ is to use the state to "calculate" the file to be played in the play command. This would add increased flexibility and shorten the program. There are a couple of ways to do this...
With the code below, you only need the four sound files (1.mp3 - 4.mp3) on the thumb drive. However, with a slight change to the program, you could have any number of different sounds and it would play them in order with each activation.
' =========================================================================
'
' File...... Haunted_Room2.BS1
' Purpose...
' Author.... Liam Ferris
' Copyright (c) 2009 Liam Ferris
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... lpferris@gmail.com
' Started... 17 NOV 2009
' Updated... 17 NOV 2009
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================
' -----[ Program Description ]---------------------------------------------
'
' This program is meant to haunt a room in a house by playing quiet whispers
' as unsuspecting victims trigger a PIR as they pass the room. As the night
' goes on, the intensity builds and louder whispers are played. As the
' intensity grows, a light will begin to flicker and the whispers will get
' louder and louder.
' -----[ I/O Definitions ]-------------------------------------------------
SYMBOL RX = 7 ' SETUP = UP, no ULN
SYMBOL TX = 6 ' SETUP = UP, no ULN
SYMBOL Trigger = PIN5 ' ULN is pull-down
' -----[ Constants ]-------------------------------------------------------
SYMBOL Baud = OT2400 ' Set baud rate for VM2
SYMBOL Addr = %11
SYMBOL IsOn = 1 ' for active-high in/out
SYMBOL IsOff = 0
SYMBOL Hold_Time = 2000
' -----[ Variables ]-------------------------------------------------------
SYMBOL idx = B2
SYMBOL relays = B3
SYMBOL counter = B4
SYMBOL state = B5
SYMBOL mp3 = B6
SYMBOL timer = W4
SYMBOL lottery = W5
' -----[ Initialization ]--------------------------------------------------
Reset:
SEROUT TX, Baud, ("VST", 13) ' VM2 - stop anything that's playing
SEROUT TX, Baud, ("VSV 0", 13) ' VM2 - set volume
' -----[ Program Code ]----------------------------------------------------
Main:
PAUSE Hold_Time
timer = 0 ' reset timer
Check_Trigger:
PAUSE 5 ' loop pad
timer = timer + 5 * Trigger ' update timer
IF timer < 100 THEN Check_Trigger ' wait for 0.1 sec input
Update_State:
state = state + 1
Handle_State:
mp3 = state / 4 + 1 ' compute the mp3 file to play
IF mp3 < 4 THEN Play_Sounds ' Only have four sounds, so on 4, reset state to zero
state = 0 ' Reached max - reset to zero
Play_Sounds:
DEBUG "Will play ", #mp3, ".mp3", CR
PAUSE 500
SEROUT TX, Baud, ("VPF ", #mp3, ".mp3", 13) ' Play a file named <mp3>.mp3
DEBUG "Played ", #mp3, ".mp3",CR
GOTO Main
END
Bigrez, thank you for the suggestion. I will give that a try too.
I started playing around, and thought it would be cool to be able to randomize the experience. So I played with some randomization equations and think I have it down. It seems to be spitting out the correct result. Just thought I'd share. :)
' =========================================================================
'
' File...... Haunted_Room_Random.BS1
' Purpose...
' Author.... Liam Ferris
' Copyright (c) 2009 Liam Ferris
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... lpferris@gmail.com
' Started... 17 NOV 2009
' Updated... 19 NOV 2009
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================
' -----[ Program Description ]---------------------------------------------
'
' This program is meant to haunt a room in a house by playing quiet whispers
' as unsuspecting victims trigger a PIR as they pass the room. Intensity is
' ransomized so that each guest will get a different experience. In addition,
' in some cases nothing will happen and the program will go to Main. As the
' intensity grows, a light will begin to flicker and the whispers will get
' louder and louder.
' -----[ I/O Definitions ]-------------------------------------------------
SYMBOL RX = 7 ' SETUP = UP, no ULN
SYMBOL TX = 6 ' SETUP = UP, no ULN
SYMBOL Trigger = PIN5 ' ULN is pull-down
' -----[ Constants ]-------------------------------------------------------
SYMBOL Baud = OT2400 ' Set baud rate for VM2
SYMBOL Addr = %11
SYMBOL IsOn = 1 ' for active-high in/out
SYMBOL IsOff = 0
SYMBOL Hold_Time = 2000
' -----[ Variables ]-------------------------------------------------------
SYMBOL idx = B2
SYMBOL relays = B3
SYMBOL counter = B4
SYMBOL state = B5
SYMBOL intensity = B6
SYMBOL timer = W4
SYMBOL lottery = W5
' -----[ Initialization ]--------------------------------------------------
Reset:
SEROUT TX, Baud, ("VST", 13) ' VM2 - stop anything that's playing
SEROUT TX, Baud, ("VSV 0", 13) ' VM2 - set volume
' -----[ Program Code ]----------------------------------------------------
Main:
PAUSE Hold_Time
timer = 0 ' reset timer
Check_Trigger:
PAUSE 5 ' loop pad
timer = timer + 5 * Trigger ' update timer
IF timer < 100 THEN Check_Trigger ' wait for 0.1 sec input
Update_State:
RANDOM state ' Randomize state value
intensity = state // 21 + 1 ' set a value for intensity between 1 and 15
DEBUG "State value = "
DEBUG intensity,CR ' Print intensity value
Handle_State:
IF intensity <= 4 THEN Low_Intensity
IF intensity <= 8 THEN Medium_Intensity
IF intensity <= 13 THEN High_Intensity
IF intensity <= 19 THEN Insane_Intensity
IF intensity > 19 THEN Main
Insane_Intensity:
DEBUG "Insane_Intensity",CR
PAUSE 500
SEROUT TX, Baud, ("VPF 4.mp3", 13) ' Play a file named "4.mp3"
DEBUG "Played 4.mp3",CR
GOTO Main
Low_Intensity:
DEBUG "Low_Intensity",CR
PAUSE 500
SEROUT TX, Baud, ("VPF 1.mp3",13)
DEBUG "Played 1.mp3",CR
GOTO Main
Medium_Intensity:
DEBUG "Medium_Intensity", CR
PAUSE 500
SEROUT TX, Baud, ("VPF 2.mp3", 13)
DEBUG "Played 2.mp3",CR
GOTO Main
High_Intensity:
DEBUG "High_Intensity", CR
PAUSE 500
SEROUT TX, Baud, ("VPF 3.mp3", 13)
DEBUG "Played 3.mp3",CR
GOTO Main
END
I like the idea of randomization, but maybe I'm not understanding your intent. I would think that since there are only four sound files, you only need to account for four random numbers: 1, 2, 3 and 4. What I believe you have coded could produce playing any one of the four sounds at any given time, right? Thus, the "intensity" check doesn't apply. The code here does the same thing but is much shorter.
Note: moved the RANDOM up into the trigger loop to get better "random" results. Also note that there's nothing that prevents another trigger from occuring while a sound file is playing.
' =========================================================================
'
' File...... Haunted_Room_Random.BS1
' Purpose...
' Author.... Liam Ferris
' Copyright (c) 2009 Liam Ferris
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... lpferris@gmail.com
' Started... 17 NOV 2009
' Updated... 19 NOV 2009
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================
' -----[ Program Description ]---------------------------------------------
'
' This program is meant to haunt a room in a house by playing quiet whispers
' as unsuspecting victims trigger a PIR as they pass the room. Intensity is
' ransomized so that each guest will get a different experience. In addition,
' in some cases nothing will happen and the program will go to Main. As the
' intensity grows, a light will begin to flicker and the whispers will get
' louder and louder.
' -----[ I/O Definitions ]-------------------------------------------------
SYMBOL RX = 7 ' SETUP = UP, no ULN
SYMBOL TX = 6 ' SETUP = UP, no ULN
SYMBOL Trigger = PIN5 ' ULN is pull-down
' -----[ Constants ]-------------------------------------------------------
SYMBOL Baud = OT2400 ' Set baud rate for VM2
SYMBOL Addr = %11
SYMBOL IsOn = 1 ' for active-high in/out
SYMBOL IsOff = 0
SYMBOL Hold_Time = 2000
' -----[ Variables ]-------------------------------------------------------
SYMBOL state = B5
SYMBOL intensity = B6
SYMBOL timer = W4
SYMBOL lottery = W5
' -----[ Initialization ]--------------------------------------------------
Reset:
SEROUT TX, Baud, ("VST", 13) ' VM2 - stop anything that's playing
SEROUT TX, Baud, ("VSV 0", 13) ' VM2 - set volume
' -----[ Program Code ]----------------------------------------------------
Main:
PAUSE Hold_Time
timer = 0 ' reset timer
Check_Trigger:
RANDOM state ' Randomize state value
PAUSE 5 ' loop pad
timer = timer + 5 * Trigger ' update timer
IF timer < 100 THEN Check_Trigger ' wait for 0.1 sec input
intensity = state // 4 + 1 ' Compute a value for mp3 file between 1 and 4
Play_MP3:
DEBUG "Intensity=", #intensity, CR
PAUSE 500
SEROUT TX, Baud, ("VPF ", #intensity, ".mp3", 13) ' Play a file named <intensity>.mp3
DEBUG "Played ", #intensity, ".mp3",CR
GOTO Main
END
That certainly does optimize the code there. My idea for the value of 1 through 20 and IF-THEN is so that I can adjust the frequency of certain events. For example, if I want more low intensity triggers, I can assign a larger number of values to that event. I also just added a section called "Nothing" which will just pause the program and not trigger a sound, to add that much more mystery to it. I also plan to add sections that will just flash a light or do other things too. This is basically just the skeleton of what it will hopefully become.
Even though Hold_Time is only 2 seconds at this point, in practice it will be increased to two minutes or so, which will hopefully prevent the triggering of another event while one is in process. If you have any better ideas, they are always appreciated.
And BTW, this is great conversation and I really appreciate all of the help. I finally feel like I'm "getting it." And considering that the particular Prop-1 that I'm using for this project says "ParallaxEFX" on it, it's probably about darn time that I "get it." :)
One last quick note on this program: Using bytes to store state and intensity was my mistake. They should be words, otherwise the equation spits out the same numbers over and over. Just an FYI for anyone who might want to use this thing.
Liam
Always use the smallest variable type possible. Are you really going to have more that 255 states? If not, stick with a byte. While doing calculations the BS1 uses 16-bits working variables so you don't have to worry about under-flow if the result of a calculation is a byte.
Thank you for the suggestion, Jon. I'll change my numbers around and use bytes instead. I think my problem was when I was asking for a number from 1 to 1000 and using a byte that things were acting funny and not really randomizing at all. I'll give it a gander and let you know how it works out. Thanks!
That worked just fine, thanks Jon. I'm now using bytes for lottery and intensity and a value from 1 to 100 to determine the event.
Now that the framework is built out, I need to actually add some sounds and start getting the RC-4 going. Cool stuff!
I always use a word for my random value (lottery) -- bytes will only hold values between 0 and 255. Once I see your new framework I'll be able to give you additional guidance.
Here is the new program. I changed my lottery value to a word as requested, and am much happier with the random numbers that it's spitting out. Any guidance on other ways to make this work better is always appreciated.
' =========================================================================
'
' File...... Haunted_Room_Random.BS1
' Purpose...
' Author.... Liam Ferris
' Copyright (c) 2009 Liam Ferris
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... lpferris@gmail.com
' Started... 17 NOV 2009
' Updated... 19 NOV 2009
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================
' -----[ Program Description ]---------------------------------------------
'
' This program is meant to haunt a room in a house by playing quiet whispers
' as unsuspecting victims trigger a PIR as they pass the room. Intensity is
' ransomized so that each guest will get a different experience. In addition,
' in some cases nothing will happen and the program will go to Main. As the
' intensity grows, a light will begin to flicker and the whispers will get
' louder and louder.
' -----[ I/O Definitions ]-------------------------------------------------
SYMBOL RX = 7 ' SETUP = UP, no ULN
SYMBOL TX = 6 ' SETUP = UP, no ULN
SYMBOL Trigger = PIN5 ' ULN is pull-down
SYMBOL Light = 4
' -----[ Constants ]-------------------------------------------------------
SYMBOL Baud = OT2400 ' Set baud rate for VM2
SYMBOL Addr = %11
SYMBOL IsOn = 1 ' for active-high in/out
SYMBOL IsOff = 0
SYMBOL Hold_Time = 2000
' -----[ Variables ]-------------------------------------------------------
SYMBOL idx = B2
SYMBOL relays = B3
SYMBOL counter = B4
SYMBOL intensity = B5
SYMBOL flicker = B6
SYMBOL timer = W4
SYMBOL lottery = W5
' -----[ Initialization ]--------------------------------------------------
Reset:
SEROUT TX, Baud, ("VST", 13) ' VM2 - stop anything that's playing
SEROUT TX, Baud, ("VSV 0", 13) ' VM2 - set volume
' -----[ Program Code ]----------------------------------------------------
Main:
PAUSE Hold_Time
timer = 0 ' reset timer
Check_Trigger:
RANDOM lottery ' Randomize state value
flicker = lottery // 255 + 1 ' Set a value for variable flicker
DEBUG flicker,CR ' Print flicker value
IF flicker <= 3 THEN Flash_Light ' Randomly flash a light while waiting for a trigger
PAUSE 5 ' loop pad
timer = timer + 5 * Trigger ' update timer
IF timer < 100 THEN Check_Trigger ' wait for 0.1 sec input
Update_State:
intensity = lottery // 100 + 1 ' set a value for intensity between 1 and 100
DEBUG intensity,CR ' Print intensity value
Handle_State:
IF intensity <= 20 THEN Low_Intensity
IF intensity <= 40 THEN Medium_Intensity
IF intensity <= 60 THEN High_Intensity
IF intensity <= 80 THEN Insane_Intensity
IF intensity > 80 THEN Nothing
lottery = 66
Insane_Intensity:
DEBUG "Insane_Intensity",CR
PAUSE 500
SEROUT TX, Baud, ("VPF 4.mp3", 13) ' Play a file named "4.mp3"
DEBUG "Played 4.mp3",CR
GOTO Main
Low_Intensity:
DEBUG "Low_Intensity",CR
PAUSE 500
SEROUT TX, Baud, ("VPF 1.mp3",13)
DEBUG "Played 1.mp3",CR
GOTO Main
Medium_Intensity:
DEBUG "Medium_Intensity", CR
PAUSE 500
SEROUT TX, Baud, ("VPF 2.mp3", 13)
DEBUG "Played 2.mp3",CR
GOTO Main
High_Intensity:
DEBUG "High_Intensity", CR
PAUSE 500
SEROUT TX, Baud, ("VPF 3.mp3", 13)
DEBUG "Played 3.mp3",CR
GOTO Main
Nothing:
DEBUG "Nothing", CR
GOTO Main
Flash_Light:
DEBUG "Flash Light"
HIGH Light
PAUSE 1000
LOW Light
GOTO Check_Trigger
END