Rewinding Sound - Time Reverse WIP (Post 12)

Here is a small demo I created on time reversing.

This basically only works through the physics so far but I am planning to add a few more things. I was inspired by a game called Braid to do something like this.

Features: (Not all of them are on the latest demo)

  • Physics Rewind
  • Armature Animations Rewind
  • Object Adding/Removing Rewind
  • IPO Rewind

– If you have any ideas, suggest them below–

Using the functions in the demo:
You can access these classes by importing “Functions”.

Playing IPOs


<b>ipo = playIPO(owner,start,end)</b>
owner:
   - Accesses "IPO_play" in the IPO object
   - Type: GameObject

start:
   - Start of IPO
   - Type: Integer

end:
   - End of IPO
   - Type: Integer

<b>ipo.play(loop)</b>
loop:
   - Once to play or loop
   - Type: Boolean
      - False: Plays once
      - True: Loops forever

<b>WORTH NOTING</b>
1. IPO objects that play during time reverse must have the property "IPO_play"
2. Must have always sensor (true pulse) connected to F Curve Actuator with 'Property' play mode.
3. The script must be connected to an always sensor (true pulse)
4. The script must run on the first tick

<b>Example Script</b>

from bge import logic
from Functions import *
own = logic.getCurrentController().owner

ipo = playIPO(own,1,60) # Sets values
def main(cont):
ipo.play(0) # Plays animation once



Playing Armature Animations


<b>action = playAction(controller,actuator,owner)</b>
controller:
   - Accesses functions
   - Type: Controller

actuator:
   - Accesses functions
   - Type: Actuator

owner
   - Accesses properties
   - Type: Game Object


<b>action.set(action name,start,end,loop,different)</b>
action name:
   - The name of the action you want to play
   - Type: String

start:
   - Start frame of the action
   - Type: Integer

end:
   - End frame of the action
   - Type: Integer

loop:
   - Animation looping
   - Type: Boolean
      - False: No looping
      - True: Looping

different: #&lt;-- Temporary 
   - Animation different from before
   - Type: Integer

<b>action.play()</b>
   - Plays the animation you set
<b>
WORTH NOTING</b>
1. You must have the property "Action_play" on the animation object
2. You must have an actuator connected to the python script playing in property mode
3. The script must run on the first logic tick
4. You must run the init() method in the playAction class

<b>Example Script</b>

from bge import logic, events
from mathutils import *
from Functions import *

cont = logic.getCurrentController()
own = cont.owner
action = cont.actuators[‘actions’]
playAct = playAction(cont,action,own) # Setting Values
playAct.init() # Needed for the script to run on the first frame

def main(cont):
own = cont.owner

if not 'init' in own:
    own['init'] = True

if not own['rewind']: #Check if time is moving backwards
    if keyDown(events.UPARROWKEY):
        <i>playAct.set('player_walk',0,40,1,0) # Setting walk values</i>
    else:
        <i>playAct.set('player_idle',1,1,1,1) # Settling idle values</i>

<i>action.owner['action_current'] = own['Action_play'] #This is not on an armature so I'm copying the frames onto the armature frames</i>
<i>playAct.play() # Play the animation</i>


Spawning Objects


<b>spawn = Spawn(spawner,object,amount,deadzone)</b>
spawner:
   - The empty/object that spawns the objects
   - Type: GameObject

object:
   - The object being spawned
   - Type: GameObject

amount:
   - Total amount of spawned objects allowed ever
   - Type: Integer

deadzone:
   - The space where "dead" objects go
   - Type: Position Vector

<b>spawn.addObject(force)</b>
force:
   - The force put onto the object when spawned
   - Type: Speed Vector

returns the object added (can be used to manipulate it)

<b>spawn.endObject(object)</b>
object:
   - The object you want to go into the deadzone
   - Type: GameObject

<b>spawn.inters(interval)</b>
interval:
   - Sets the intervals in which you want objects to be added
   - Type: Integer

<b>spawn.doIntervals()</b>
   - Adds the object to the previous set interval

<b>WORTH NOTHING</b>
1. The objects cycle with each other, they aren't actually being deleted
2. The script must run on the first tick

<b>Example Script</b>

from bge import logic, events
from mathutils import *
from Functions import *
cont = logic.getCurrentController()
owner = cont.owner

spawner1 = Spawn(owner,‘box’,10,Vector([100,100,100])) # Sets values
def main(cont):
if keyHit(events.SPACEKEY):
spawner1.addObject(Vector([0,0,-20])) # Adds object with velocity
spawner1.inters(50) # Intervals, 60 ticks = 1 second (usually)

else:
spawner1.doIntervals() # Runs intervals specified above



The demo isn’t going to be in my main project, it’s actually something I want to try out for an upcoming event!

I would put up a screenshot but do you really want to see the wire frame of the default cube and a plane?

Problems:
The problem I see ahead is concerning RAM. The engine will probably start to slow down once it has run for a while. I don’t know what to really do about that but I was thinking actually saving the information on to the hard drive and then loading it when I reverse time. Kind of like dynamic loading and freeing. Would this work?

And before anyone tells me. There is a problem with the adding/removing objects. Once you cycle through them once, if the 1st objects added had been rotated then they will spawn rotating. I’ll see if I can fix it. I’ve tried many things to do so, but none of them are working!

Setup:
Press Space to reverse time
Anything that has the property called “time” will have its physics simulation reversed.

The up arrow key animates the legs

Brief Explanation:
I have a timer that counts every tick. Each of these ticks is an item in a dictionary. Each tick defines a dictionary of objects and these objects define their states at the current tick.

Example:

Time Dictionary -&gt; Tick 1, Tick 2, Tick 3, Tick 4, ...
     Tick 1 -&gt; Player, Enemy, Camera, ....
          Player -&gt; Position, Orientation, Linear Velocity, Angular Velocity, ...

When I reverse time, the timer stops counting up and instead it counts down. In each tick, I get the objects’ states and replace them with the ones in the dictionary. Then the process repeats; simulating reversing time.

End:

The concept is actually quite simple, but it produces a nice effect.

The demo is a little glitchy because physics will not will not always do the same at different times. If there’s a small change in the objects position or orientation, the physics can change dramatically from one time to another.

The .blend is in the attachments! Please give suggestions. I’m not the best programmer so if you know of a better and more efficient way of doing this I’d gladly like to hear.

Enjoy!

Attachments

time.blend (419 KB)

but it is really cool!!

congraturations!!!

the animation semm right , yes is not ever exactly the same , but after “100 rewind” all object here again in the right position.
so, i think which some little inaccurancy can be due by float number (little difference which can become more big but not because the error is big!)

i not see issue with RAM(I have only 2GB)

certainly if the list is never cleared the RAM continues to grow.
I instead would put an upper limit of time (some minutes)
after which the old tick are removed,this solve the potential issue with RAM (only my opinion of course)
the property “time” on the obj , maybe can be another more specific as “rewind” or something just to avoid confict

great work!!!

with many obj i noticed that:

usually is pretty fast , but there a “peak” which make jump the logic to 10/12%(from 2/3%) for few frame

I noticed also which your style of writing is changed a “bit” (make complex things help on this :smiley: )

@MacroIT: Thanks! All I have to do to limit RAM usage is have an if statement in the record method that resets the tick timer to 1 if it gets too high. You know what? I think I will change the affecting property from time to rewind, because now it’ll make more sense…

@Everyone: I just finished reverse animations with armatures… Up next is adding and removing objects. I’ll put up a demo sometime tomorrow with the added features…

Nice. The logic’s pretty low - five player objects went up to 0.7-0.9% (I have an AMD Athlon XP II CPU). Great job. I could see this being used for most game uses (online FPS’s, for example, with only 16 players in a match). I’m not sure if you’re doing this already, but are you adding a gravitational force upwards and nullifying the objects’ linear velocity when rewinding?

Hey, thanks! No, I’m not doing that. Should I?

I updated the attachment above so people can see that armature actions can now be reversed. Sadly, you can’t really see it being reversed because my animating skills are bad. :confused: But if you guys fix it up, it should work fine! I also added the controls for the player above. I had to scrap the blendin between animation though because it’s too difficult for me to do. Activating and deactivating actuators can get complicating when reserving time…

Well, it would probably help fix any physics issues. Think about it - you’re moving objects around by code, and the physics engine is also applying gravity and moving objects according to their linear velocity. If you nullify those, then physics errors may not be nearly as apparent, though I didn’t see any issues when I tested it out.

Oh yeah, I had issues like that before, but I fixed it by just suspending the dynamics of all the objects being affected by time reverse. So that’s why you don’t see any of those issues.

This is awesome, I loved it, congratulation!

This is soooo cooool!! can i use it for a game?

EDIT: also is there anyway of making it so that only objects that have the mouse cursor and left button pressed will rewind?

@leonnn: Thanks!

@mrn: Thanks, and you can use it for whatever you want. I put it in the resource section for a reason!

I’m not totally sure what you mean by,

only objects that have the mouse cursor and left button pressed will rewind?

I’m assuming two things…

You want only objects that have the mouse sensors to have their time reversed.
Solution - Add the property “rewind” to all the objects with those specific sensors

You want to rewind time with the left mouse button.
Solution - That can be fixed in the python script “TimeControl.py”

Change this line,


def time(cont):
    if keyDown(events.SPACEKEY): #&lt;---- This line
        timeCont.rewind()
    else:
        timeCont.record()

To this,


def time(cont):
    if logic.mouse.events[events.LEFTMOUSE] == logic.KX_INPUT_ACTIVE: #&lt;---- New line
        timeCont.rewind()
    else:
        timeCont.record()

That should work.

-----------------------------------------------

@EVERYONE:
I was also able to update something else!
You can now add and remove objects from the scene… Kind of! It’s actually almost impossible with blender to actually remove or add objects, then reverse time to add objects where they were removed, and remove objects where they were added(due to the “names” of the objects always changing). I instead went around the problem; I created a custom spawn. All you need to know is that the objects aren’t really adding or being removed :slight_smile: I’ll post an update later when I finish polishing it.

Hey everyone!
I am happy to announce that I was able to find a way to rewind sound. A little tricky (mostly because I didn’t know how to use BGE’s audaspace) but I got it! It’s only working for only background music (so far).

Here’s a different demo file I used to make it. Use the spacebar to reverse time.

http://filebin.ca/0537db <-- This a filebin.ca link, if it ever goes down, message me.

Originally I was using this song as the testing for reversing but I wasn’t sure if it was against the rules to post copyrighted music on BA, so I changed it to a soundtrack from YoFrankie.

Brief Explanation:
You can’t reverse the same piece of music from the point it’s being played at. Instead you must have two pieces of the same music, one in normal time and one in reverse time. Then you line them up when you rewind time. I’ve tried my best to illustrate it in the following…

B = Beginning
E = End

B 0 1 2 3 4 5 6 7 8 9 10 E - Normal Soundtrack Timeline (seconds)
E 0 1 2 3 4 5 6 7 8 9 10 B - Reverse Soundtrack Timeline (seconds)

The bold numbers are the places in time where the music is playing the exact same thing. Remember, the beginning of the normal soundtrack is playing in the end of the reversed soundtrack. Meaning that the only time the soundtracks are playing the exact same thing at the exact same time is in the middle.

Ex1
B 0 1 2 3 4 5 6 7 8 9 10 E <- At Exactly 3 seconds on normal time…
E 0 1 2 3 4 5 6 7 8 9 10 B <- Reverse time is at 7 seconds…

Ex2
B 0 1 2 3 4 5 6 7 8 9 10 E <- At Exactly 6 seconds on normal time…
E 0 1 2 3 4 5 6 7 8 9 10 B <- Reverse time is at 4 seconds…

Ex3
B 0 1 2 3 4 5 6 7 8 9 10 E <- At Exactly 0 seconds on normal time…
E 0 1 2 3 4 5 6 7 8 9 10 B <- Reverse time is at 10 seconds…

Do you notice the pattern?

Time in Reversed Soundtrack = Length of Soundtrack - Time Gone in Normal Soundtrack

And to bring it back… It’s the same thing!
Let’s check if it works:
Ex1: 7 = 10 - 3
Ex2: 4 = 10 - 6
Ex3: 10 = 10 - 0

So you can see what basically makes up the idea.

End:
I have to admit that I didn’t know how to use Audaspace this morning, the way I learned was by looking at SolarLune’s scripts in his Sparky demo. So thank you SolarLune!

I’ll post a mini document tomorrow on the playMusic class I made to play the soundtrack.

Nice. It doesn’t seem to rewind anything but the sound in the filebin example, but maybe that’s what it’s supposed to do. As for reversing the sound, there’s a way to do it dynamically.

One way is to use the Audaspace Reverse() function to create a reversed factory for each sound , which is easier than packaging reversed versions of the song and sound files. Another is to use the BGM playback handle’s position property, and simply back that up by the same rate that it plays every frame. It should (theoretically) be rapid enough to sound like playing the song (or any sound) backwards.

Still, great work!

regard the RAM and the dictionary limitation size

a solution easy is change the dictionari key , from string, to number

from
D= {“1”: {}}
to
D= {1: {}}

then add a “range max” after that the dictionary can be clean

(PS: I not see again the last blend)

regards

Are you serious? I was thinking there had been something like that. That’s exactly what I did for the armature animations and IPOs. I was hoping I could do it with audio, but looking at the API references I never noticed anything like that. Maybe I missed it. I’ll try this way tomorrow and maybe make a new class for it.
As for the “Audaspace Reverse()”, I knew about this way but I thought that maybe people would want to filter the reversed soundtrack instead of just leaving it as it is.
I only made this .blend to reverse sound, so that’s why nothing else rewinds. It’s easy to add it into the actual demo .blend though!

@MacroIT
I have it basically setup that way, I just convert it into a string because it’s easier for me, as the programmer, the identify lists from dictionaries. I am planning to do this sometime in the future but in all honesty, I want the recording to be able to last 1 hour at least.

Thanks for the suggestion :slight_smile:

Quite a nice resource!