Update clocks.py, add functionality and refactoring

A much needed update that brings some new and improved functionality to the script.

- GPU clock settings now are set via the API. This removes a key platform dependency and improves portability (untested).

- Core clock stepping now follows a trapezoidal waveform. This greatly shortens the settling time between memory clock steps, smooths out thermal cycles when stepping through wide core clock ranges and possibly improves GPU stability during tuning.

- Writes now occur at every half cycle (default) or every full cycle. This facilitates the change in core clock stepping while still maintaining a sorted output.

- Added a check for core clock and memory clock intervals against each of their ranges. Their ranges must be divisible by their intervals or else the script will exit.

- Some refactoring was done to improve extensibility.