Saturday 28 October 2017

Maya TD tips - that awesome 'toolkit' you always wanted...

I got tired - tired of seeing icons on shelves in Maya disappear and noting that even when working, flipping to shelves to change the tool set that was being used meant the pipeline tools that I'd painstakingly developed would be hidden in a shelf that probably wouldn't be set back again when needed.

Friday 13 October 2017

Maya swatch headaches be-gone!

This was something that frustrated me this afternoon, so much that I thought I'd slap this very short and concise blog entry for anybody interested...

I loaded up a rather complex project to test that had been set up to use VRay materials, and had been choking up and causing havoc on the render-farm here. 

Sunday 1 October 2017

100 days - Exhibited, and over for 2017!

Yus!  100 Days is now officially over for 2017...

In one way, its a relief since I can now just continue with the norm's of life without that 'must do 100 days' thought lingering in the back of my mind.   In another way, its also sad that it was a good way to enforce drawing practice - however it has left me with a habit to just do it so its worked out.

Wednesday 16 August 2017

More TD tips - Trello for task management

In any pipeline, communication is key - sharing and passing data back and forth, whether its from application or process to another or from a manager to an artist.  Over the years I've developed plenty of scripts to manage file naming, server logging and automating processes.  I'd also built a SQL feedback and approval system that didn't see the light of day - and after reviewing what I'd done, it was a great learning process but it was fairly limited.

Thursday 1 June 2017

100 days - 2017 edition

Foolishly, I figured I'd again take some time to do something creative for 100 days.  This time I've decided to keep it pretty much to one theme...  Caricatures and Comics... as its an area I've not spent a whole lot of time playing around in.

Where 100 days comes in useful is as a way to provide plenty of compulsory "practice" time.  When you have an audience (ie. the interweb) watching you, there's kinda this whole drive to not look lazy in front of the world. lol!

Saturday 4 March 2017

Restoring the 2600 collection - one box at a time

I've been buying carts for my 2600 to increase my library lately...  However as expected over the years, most carts end up becoming loose and without boxes, manuals, etc.  While I don't mind that, for a collector, it would be great if there was some way to get those missing boxes and at least display those loose carts in all their original off-the-shelf glory...

Sunday 15 January 2017

Beeps and bleeps - playing Speccy music in python

While I was messing about with converting old UDG graphics to PNG files, I figured one of the other things I was curious to recreate was the beepy music from the ZX Spectrum.  BASIC code loaded with BEEP commands created that "I wonder what does that sound like?" curiosity that made me wonder just how easily I could use python to listen to the classic Sinclair hits of the 80's...

To export or just listen?

I tried two methods.  One was to make use of python's wave module.  This is a module that allows you to work with audio files.  That includes the ability to both read and write.  Being able to export the music to a .wav mean't that it could be bought into those recreated games and used.

One problem I did run into was getting the beepy-sound out nicely.  I tried many of the tried-n-tested code examples online that generated a sine wave - however while it worked, the final audio sounded pretty odd and didn't have that nice clean bleep I was expecting.  I figured I'd come back to this later...

Exporting aside, I felt there must be a better way to just listen to the music - afterall, its that curiosity of hearing what it sounded like I was after.  Lucky python has a module designed just for the task... The winsound module.  I also wanted to create pauses in the music, so I imported the sleep function from the time module as well.

import winsound
from time import sleep

Yup, winsound has a Beep function (note the uppercase B).  Much like the ZX Spectrum's own beep, you just pass the note and duration.  Sounds like it should be a real doddle!

Hmmm, note vs. frequency

ZX Spectrum audio uses semitone numbers.  A value of 0 is middle C.  1 is the next semitone of C# / Db, 2 is D and so on.  However winsound.Beep required a frequency value (in hertz).  How do I translate that number into a frequency?

Did I mention I suck at maths?

Maths was never my strong suit at school, but luckily for me that's where the internet comes in with the answers!  The formula for calculating a frequency is simply

Frequency = base-note * a^semitone

Where base-note is the lowest frequency of your musical scale (in this case, I decided to go for 3 octaves below which is 32.70 hertz).  The value of a is calculated as the 12th root of 2 ( in nerdy math terms, its 2^(1/12) ).

Maths always looks easier in code

I created a function to calculate the correct frequency from the beep value.  I calculated this from the lowest frequency of 32.70...  As I knew middle C (beep value of 0) was three octaves higher, I just added 36 (which was 3 * 12 semitones) to the value first...

In case you're wondering about the code below, 0.083 is 1 / 12.

def beepFreq(ZXVal):
    zxNote = ZXVal + 36
    a = 2.0 ** 0.083
    freq = 32.70 * (a**zxNote)
    return freq

Getting them tunes down...

The music data itself I passed as a sequence of tuples in a list, copied directly from the BEEP parameters in the spectrum listing.  This isn't the most musical of pieces, but it came from a listing so it was a good test...

As there were often pauses added through music, I needed a way to indicate this.  I used a note value of 99 to signal a pause.

musicData = [ (.1,0),(.1,0),(.1,2),(.1,2),(1,0),(1,99),
              (.1,0),(.1,4),(.1,4),(.1,0),(.1,0),(.1,2),(.1,2),
              (.1,-1),(.1,-1),(.1,0),(.1,0)]

Looping through this list, I read the duration and note value.  The duration is slightly different between the winsound.Beep function, and the sleep() function that I used to introduce pauses.  The Beep function requires the length in milliseconds.  This is simply the duration from the list multiplied by 1000.  The sleep function just uses the value (number of seconds) directly.

The rest of the code was a piece of cake.  I feel there's no real explanation necessary as the code can speak for itself...

for musicPlay in musicData:
    # Calculate the duration (in milliseconds)
    duration = int(musicPlay[0] * 1000)
   # Work out if we play a note, or whether this is a pause
    if musicPlay[1] == 99:
        sleep(musicPlay[0])
    else:
        note = int(beepFreq(musicPlay[1]))
        # Call the Winsound Beep
        winsound.Beep(note,duration)

Budum-tish!

And there you have it.  Go grab those old ZX Spectrum basic listings and type in the beep values to enjoy all of those bleepy tunes that were part and parcel of games in the 80's

Saturday 14 January 2017

Retro bytes to PNG pixels with Python

After a long break from doing any retro game recreation in Python, I decided that since I had a few old personal game listings laying around from my ZX Speccy days that the idea of converting these to python could be fun at some later date.

However one thing the ZX Spectrum had that we didn't see on the ZX81 (with its lack of any real graphics capability) was user defined graphics, or UDG's as they were termed.