DISCLAIMER: Unsure if title even fits and this is my first post so I'm learning how to organize this
CODE BACKSTORY:
I create fractal flames (iterated images) using Apophysis7x and open the .flame file (this file is not rendered, it simply holds the information to open in another editor) in Fractal Fr0st where I can automate for example, an iteration to be constantly rotated thus creating an animation. Fractal Fr0st uses python for such automations however they're constant. I produce music and hope to someday complete my code below to have the rotations alternate based on the BPM of my song. I started to code on my own to produce a tick tock sequence before even editing the actual python file associated with the program (that code is not entirely important for now, but is posted at the end)
INFO SO FAR ON PROBLEM:
I know right off the bat Python is not the fastest language out there, but I am not 100% sure if my code is just not efficient enough to keep up with what I am trying to have output. Please take a look at my code and comments as I try to explain as thorough as I can what is going on.
timer.py:
import time
#Feel free to test as you'd like
#Suppose we have a song at 140 Beat Per Minute (BPM) -> There is approximately 2.33 Beats Per Second (BPS)
#So it takes approximately 0.43 (s) per beat
#So if freq = 0.43, leng = *length of song*
#This program should alternate printing "tick" "tock" (or some action that I hope to code in the future)
#The Tick Tock output should come out every (in this case) .43 seconds
class timer(object):
"takes in a frequency and duration of loop in seconds"
def __init__(self,freq,leng):
"input a frequency and duration in seconds"
#rounded to 2 decimal places
self.freq= round (freq,2)
self.leng= round (leng,2)
def ticker (self):
"Starts the time and loop to be broken when max time is reached"
counter = 0 #recorded out of curiosity to check just how many loops were made overall
ticker = 0 #alternates the "tick" "tock"
initTime = time.time() #records the initial upon starting the loop
rnded = 0 #initial rounded time set at 0 *see the first if statement below*
while True:
stop = time.time() #The time recorded during the loop *stopwatch so-to-speak*
passed = stop - initTime #The time passed from initial launch to time during the loop
if rnded == self.leng:
"When the time that has passed reaches time limit print stats and break"
return print("Loops:".ljust(10).rjust(14) + "Initial Time:".ljust(17).rjust(21) + "Time Stopped:".ljust(17).rjust(21)+ "Passed:".ljust(11).rjust(15) + "Total Ticks:".ljust(16).rjust(20) + "\n" + (str (counter) ).ljust(10).rjust(14) +(str (initTime) ).ljust(17).rjust(21)+ (str (stop) ).ljust(17).rjust(21)+(str (rnded) ).ljust(11).rjust(15) + (str (ticker) ).ljust(11).rjust(15) )
elif round(passed,2) == rnded:
"Prevents duplicates, ie: previous stopped at .9999 (1.0) and current loop sopped at 1.001 (1.0) skip"
#If your current value happened to be rounded to the previous value don't continue
#uncomment bellow for debugging
#print ("*TEST* \t Initiated: ", initTime, "\t Time stopped: ",stop, "\nTime passed: ", rnded, "\t Tick Counter: ", ticker, "\n ---")
pass
else:
"Tick tock code"
rnded = round(passed,2) #now set current time differnce value after being checked for duplicates
if rnded % self.freq == 0 and rnded != 0:
"if the time passed mod the frequency is 0 continue to execute tick tock"
if ticker % 2 == 0:
#gives stats for debugging purposes, delete, after "tick" / "tock" if desired
#prints in the meantime in the future I would like an action to be done with music in another program as precise as possible
print ("Tick \t Initiated: ", initTime, "\t Time stopped: ",stop, "\nTime passed: ", rnded, "\t Tick Counter: ", ticker, "\n ---")
elif ticker % 2 == 1:
print ("Tock \t Initiated: ", initTime, "\t Time stopped: ",stop, "\nTime passed: ", rnded, "\t Tick Counter: ", ticker, "\n ---")
ticker +=1 #only increases if tick/tock was processed
counter += 1 #counts how many times loop was accessed, use this as you'd like
def chngFreq(self, freq):
'Changes current frequency'
self.freq = round (freq,2)
def chngLeng(self,leng):
'Changes current duration'
self.leng = round(leng,2)
Example 1:
The output skips multiple "tick" / "tock" as the frequency gets faster (I was just testing for example when the frequency was at .01(s) and total time of 4(s), there should be a total of 399 ticks yet it only made it to 5 ticks. My theory is that since it does take time to go through the loop (however a very small amount of time) it may skip a tick due to some probability that before getting to the next tick from .01 to .02 before it was being rounded it could've been a tick, but the code wasn't processed fast enough. I rounded till the end to be as accurate as possible and made the "elif" portion to prevent duplicates (see code above)
Output:
>>>s = timer(.01,4)
>>>s.ticker()
Tick Initiated: 1502409793.6775877 Time stopped: 1502409793.6937597
Time passed: 0.02 Tick Counter: 0
---
Tock Initiated: 1502409793.6775877 Time stopped: 1502409793.7562232
Time passed: 0.08 Tick Counter: 1
---
Tick Initiated: 1502409793.6775877 Time stopped: 1502409793.8409605
Time passed: 0.16 Tick Counter: 2
---
Tock Initiated: 1502409793.6775877 Time stopped: 1502409793.9940765
Time passed: 0.32 Tick Counter: 3
---
Tick Initiated: 1502409793.6775877 Time stopped: 1502409794.9579115
Time passed: 1.28 Tick Counter: 4
---
Loops: Initial Time: Time Stopped: Passed: Total Ticks:
5473896 1502409793.6775877 1502409797.680171 4.0 5
Please note that occasionally the tick is only counted for 2^x ie: .01, .02, .04, .08, .16, .32... Instead of: .01, .02, .03, .04, .05, .06...
I know this is not the example that I gave in my code but it is true whenever I try a more approximate frequency such as .23 or .01, yet the larger the frequency regardless of precision ie: 4.29 it will be more likely to accurately return the "ticks" 4.29, 8.58, 12.87 etc...
Example 2
In the following example you can tell it works perfectly fine as it is given longer time to process between ticks
>>>s = timer(1,4)
>>>s.ticker()
Tick Initiated: 1502411198.8088021 Time stopped: 1502411199.8091898
Time passed: 1.0 Tick Counter: 0
---
Tock Initiated: 1502411198.8088021 Time stopped: 1502411200.8089292
Time passed: 2.0 Tick Counter: 1
---
Tick Initiated: 1502411198.8088021 Time stopped: 1502411201.81057
Time passed: 3.0 Tick Counter: 2
---
Tock Initiated: 1502411198.8088021 Time stopped: 1502411202.8121786
Time passed: 4.0 Tick Counter: 3
---
Loops: Initial Time: Time Stopped: Passed: Total Ticks:
5586557 1502411198.8088021 1502411202.8328226 4.0 4
Please let me know if any of this code is unclear, but please be sure to read each comment first and run the code/modify if needed.
Once my previous problem is resolved I hope to modify the "if x.animate:" section of the following code that is used in Fractal Fr0st.
default.py:
update_flame = False
while True:
for x in flame.xform:
if x.animate:
x.rotate(-3)
preview()
Finally thanks a million in advance I know this is really long but I am truly trying to understand what is going on with python/how it operates, regardless of what my end goal is.
Also if any other methods are faster/more efficient please let me know. Thanks!!!