Optical Illusion Mode - Extreme Rotation!

so had a further play with colour palettes

this is potentially quite a fun area to mess with in ETC, as its low cpu… (not just for spinning discs)
as above, I was using monochrome, such that I could turn the black areas to any colour, which is fun for colour animation

then I thought, why not use coloured images with a small colour palette and then start altering other colours in the colour palette, and its seems to work pretty well… and of course gives an extra dimension to play with with sound
(Im interested in what modulation possibilities work, so that the image appears to be connected to the music)

anyway so far , it sees to work best on images that have a restricted palette, just because its simpler to select the index, and also because with a smaller palette theres less dithering… though this is actually more a function of how you prep the images.

Man, it keeps getting better! You do the coding , I’ll prep the images! :wink:
Jus’ kidding, I can’t wait to play around with these patches, but for now it seems I’m more valuable prepping and testing images. I’ll get some 3-4 color examples ready and share them asap.

For this thread we can stick to rotational methods, but your new discovery already has me thinking! Who knew lo-fi color would be so versatile? lol

Happy New Year!
I have revised the images for this project. They are all indexed color PNGs. (No more 24-bit color) For now, these are all 640px sized, but I think the performance on these will be good and 320 may not even be needed. There is a variety of 2-color, 4-color and 32 color images, all with transparency (alpha). I also removed some images which just were not a good fit.

New zip attached! >> images.zip (387.8 KB)


@thetechnobear - I think these new images will work much better than the previous set. Could you update the patch on patch storage?

What do you think is next? How can we apply audio to this patch? I was thinking thinking of a few possibilities/suggestions:

Audio triggers:

  • increment image
  • random image color (8-bit 2-color)

Knob controls:

  • rotation speed
  • image scale
  • image position
  • image color fine control (8-bit 2-color)

ok, Ive updated this on patchstorage here

new images (thanks to @mkunoff) , new controls and now audio input.

controls are:
knob 1 – rotation speed
knob 2 – image
knob 3 – colour index for colour change
knob 4 – ‘foreground’ colour

midi note or audio trig – switch image
audio input – adds to rotation speed

with the limited amount of controls available on the ETC , when I played with it, this seemed the best combo

rotation speed is constant (k1) if you don’t audio coming in, or influenced by the audio volume if you do, seems to work best with ‘beats’

image selection on k2 (but you can increment with audio trig, or midi) , this was because its pretty important for scenes to be able to choose which image you want.

note: image offset cant be stored (due to the way etc works) , so when storing in a scene, you will want to make sure you have not used midi note or audio trig to advance the image. ie. its is the ‘base image index’ that is stored, from there audio trigs and midi trigs will advance the image.

foreground colour and colour work together, this one is fun…
so you select any colour (images should use indexed colour palette) and get it replaced by the foreground colour - varying this by scene, or by when switching images can produce some nice effects.

note: foreground colour, can be one of the cycling colours too.

its pretty sensitive to audio input levels, as this is changing speed rotation, and audio trigs will switch images, so experimentation is necessary.
also rotation is pretty important for this ‘effect’, and has ‘sweet spots’ - so when using audio rotation, its good to also play with knob1.

as I said, having played with the images and sound going thru these seemed to be the best combo, sure other controls would be nice, by given the ETC only has 4 knobs we are limited.

of course, using the ETC web editor its easy for users to create their own variations, if they would prefer to substitute other controls on the knobs


personalised hacks , to get you started

so ETC is all about customising modes to your taste, and music styles… so heres a couple of hacks to get your going and make this yours :slight_smile:

the most obvious one is knob 1…
currently its a constant rotation + audio angle

    chg =   ((etc.knob1 * 180) + audioangle)  

this is so that it can be used without audio input (i.e. constant rotation)

however, some users may prefer to only have it rotating IF there is audio and then use k1 as a scaling factor for the rotation, to do this change the above to:

    chg =   (etc.knob1 * audioangle)  

also if you dont want audio trigs to switch images only midi notes
then change

    if etc.audio_trig or etc.midi_note_new :


    if etc.midi_note_new :

WOW!!! :heart_eyes::hugs:

I’m sitting at my desk at work reading this and I’m starting to feel sick. Might need to leave work early… :smiling_imp::clown_face:

Thank you - thank you - thank you!! I’m going to repay you somehow for this. I’ll start by curating more images. There are some interesting possibilities with the color index idea, that i can take full advantage of. This first set images is just the beginning! Happy Friday!

1 Like

Played with this over the weekend and it’s really awesome. The real winner imo is being able to cycle through the color index. @thetechnobear

It seems this code is responsible for cycling through the color index, yes? Can you give me a little more explanation what is happening here so I can potentially use it on other patches (including ones which don’t rotate.)?

if angle < -360 : angle += 360
    origimg = images[image_index] 
    img = pygame.transform.rotate(images[image_index],angle)
        cidx = 1
        pal = len(origimg.get_palette())
        cidx = int(round(etc.knob3 * pal,0))
        cidx = 0

Also, considering I want to expand further on the “SpinningDiscs” image set, do you think it makes sense to provide the image set on patchstorage.com?

1 Like

easy question first… yes , I think it makes sense to provide the images separately :slight_smile:

colour palette code , is just this bit

        cidx = 1
        pal = len(origimg.get_palette())
        cidx = int(round(etc.knob3 * pal,0))
        cidx = 0

it needs to be in a try/except block, to handle the case where the there is no colour pallet e.g. just a plane rgb image

        pal = len(origimg.get_palette())
        cidx = int(round(etc.knob3 * pal,0))

knob values are 0 to 1, so we simply use the position of the knobs (say half way around = 0.5) and then multiply this by the number of colour in the palette.

then the set_pallette_at, simply changes the colour at that position… with a colour selected by knob4 (this is what etc.color_picker() does)

a couple of things:

  • colour_picker() , has a few basic colours in some positions, but in other positions it returns different values each time its called, so each frame (the colour can be entirely random or just a subset, see the etc_system.py for the code) , thats how you get the changing colours.
  • colour palettes
    ok, a bit of background, just in case someone reads this, and is not clear on what the colour palette is.
    when you save an image with a colour pallet what it does is build a table (the palette) which has all the colour used (more accurately , you specify the max number of colours e.g 1 bit or 8bit, so 2 or 256 colours) , then each pixel is stored as an index into that table… eg. black might be at 0, a shade of red at 5… so to switch colours, you just need to update the palette, e.g. so that pallet[0] = blue , and now all the black turns to blue.
    (the original intention of colour palettes was to save memory, since there are a large number of pixels, so if you save just an index, thats a lot less memory than saving the rgb colour … its kind of a compression algorithm)

Thank you so much @thetechnobear!

The image set is now uploaded to patchstorage.com - https://patchstorage.com/spinningdiscs-image-set/

1 Like

@mkunoff & @thetechnobear - this mode is awesome. Thanks for making it! Been making some images to spin and will share them when they’re finished up! Here’s one:


This is so beautiful! Thank you all!!!

great to see you having fun with it @chrisk :slight_smile:

So glad to see people enjoying this! @thetechnobear did all the heavy lifting. :raised_hands:

You’re awesome! Thanks for making this! <3

@thetechnobear if I’m running this on the Organelle OTC. What would the folder setup look like?
Would it look like this?


Also, if I’m looking to use the 320 set as well as the 640 set. Will I place both of them into the SpinningDiscs folder?

should just be

but if you download from patchstorage, unzip and put in your modes directory, it should just work

the just add stuff to the images folder you find there.

you just needs to put them in the images directory

bare in mind, with OTC/ETC all images (for all modes) are loaded into memory, so memory can get short if you start adding lots of images … also the bigger the images the slower the frame rate.
so its a trade-off, depends on what you want etc.

what id recommend is trying them , and then keeping the ones you like the most.

1 Like

Did you ever try what @oweno suggested here “ETC memory best practices

hmm, looks like there isn’t a specific way to stream from disk, you still have to load it into a variable, but the difference would be instead of loading many images into an array in the setup() section of the mode, it could just load them as it needed in draw() :

img = pygame.image.load('first-image.png')
# replace img with new image
img = pygame.image.load('second-image.png')

so this would draw 2 images on the screen, but only require memory for one.

err, that is not what id call ‘best practice’ , rather a ‘trade-off’

the issue is, if you call load in render, then its very likely your display will stutter when you switch images (especially if its a large image) - so when are you willing to accept this? I doubt you would in a live set.

the only way to handle this better, would be to load images in a background thread, but I doubt this will help much considering the ETC/Organelle are single core (and python is notoriously bad with thread synchronisation)

so yeah the choice is, do you want your modes to be stutter free or have lots of them?

for me, this is an area I’ve considered improving on OTC…

I think the UI should support a concept of a ‘performance’ (or scenes?),
such that you can have lots of modes on the disk, but you only load up a subset of them for performance.

this way you can optimise the resources for a live set , but you can have loads of modes on the disk for when your designing you ‘set’
this concept could be extended to images, so that you ‘tag’ which images you want to have in the set.

this is really just a organisation function, which you can do manually, buts its really quite painful.

yepp, that is the right approach.

I could imagine to have the ODS button like a “Shift”-key.
Now: how do we recognize double keypresses like “ODS”+“next-Scene”. I don’t think, that the pygame.K_-Function can react on two keys pressed at the same time…