Archive for December, 2007

Simplifying code using states

Wednesday, December 19th, 2007

Lately I have been refactoring czPlayer to add more features and make future maintenance easier.
Some parts of the code are almost 10 years old, when I first started playing with sound coding.
Needless to say, my code style and quality has improved a lot in 10 years, and it’s a funny thing to look at code this old. :)
As I was refactoring the code, I found a lot of ambiguities and redundancies caused by member variables added over time.
Let me explain….
I had a class responsible for MOD processing, and some of the member variables were:

[code='cpp']
class MODModule
{
// ...
bool m_loaded;
bool m_playing;
bool m_paused;
bool m_reachedEnd;
};
[/code]

What’s the problem with this approach ?
Let’s see…
Suppose I want to call methods on the MOD object (e.g: Pause(), Resume(), etc)
I need to make some checks in each method.

To pause…
[code='cpp']
if (!m_loaded || m_playing || m_paused)
return SOME_ERROR;
m_pause = true;
// ... do pause stuff
[/code]

Then to resume…
[code='cpp']
if (!m_loaded || !m_paused)
return SOME_ERROR;
m_paused = false;
// ... do resume stuff
[/code]

When the MOD finishes playing, I needed something like this…
[code='cpp']
// ... some code that checks for end
m_reachedEnd = true;
//ups... How about m_playing, m_paused?
//We need to change their values, so we don't break code elsewhere
m_playing = false;
m_pause = false;
[/code]

And similar things when playing, stopping, etc.
See the problems?

  • We need checks for multiples variables
  • We need to make sure the variables have valid values in relation to each other
  • What if we want to add an extra state? For example, “bool m_fading”. We would need to examine a lot of code to check how the other variables are used, and hardwire this new one somewhere. Every time you need to add an extra variable, you’ll need to check more and more code to make sure everything is ok.

Now look at the meaning of the variables. They are mostly mutually exclusive.

  • If it’s playing, it can’t be paused and hasn’t reached the end.
  • If it’s paused, it’s not playing, and hasn’t reached the end yet.
  • … and so on….

The more data members a class has, the harder it gets to keep the object in a valid state, so, the less data to manage, the better. Less maintenance and less bugs.

One technique I use a lot when trying to simplify code is to look at it with state diagrams whenever possible.
Here it is what happens (kind of) with instances of the MODModule class:

mod_states.png

I can easily translate it to code with enums.

[code='cpp']
enum MODState
{
MOD_STATE_NOT_LOADED,
MOD_STATE_STOPPED,
MOD_STATE_PLAYING,
MOD_STATE_PAUSED,
MOD_STATE_REACHED_END
};

class MODModule
{
// ...
MODState m_state; // Now we have only one variable
};
[/code]

This approach is a lot easier to maintain, and less error prone.
Now the code in most functions become something like this:

To play…
[code='cpp']
if (m_state!=MOD_STATE_STOPPED)
return SOME_ERROR;
m_state = MOD_STATE_PLAYING;
// ... do play stuff
[/code]

To pause…
[code='cpp']
if (m_state!=MOD_STATE_PLAYING)
return SOME_ERROR;
m_state = MOD_STATE_PAUSED;
// ... do pause stuff
[/code]

To resume…
[code='cpp']
if (m_state!=MOD_STATE_PAUSED)
return SOME_ERROR;
m_state = MOD_STATE_PLAYING;
// ... do resume stuff
[/code]

To stop…
[code='cpp']
// We cannot stop if it's not even loaded yet, or it's already stopped
if (m_state==MOD_STATE_NOT_LOADED || m_state==MOD_STATE_STOPPED)
return SOME_ERROR;
m_state = MOD_STATE_STOPPED;
// ... do stop stuff
[/code]

The code may look similar, but it’s a lot less error prone, easier to follow and maintain.
Looking at the State Diagram, I could easily squeeze in a “Fading” state and understand the conditions to enter or leave that state.

As a bonus, using enums will enforce more rules and help you out with errors the compiler might catch. Always prefer compile-time errors over run-time errors. ;)

czPlayer 0.1.1 released

Sunday, December 16th, 2007

New release of czPlayer.
Just a few bug fixes in the internal mixer, and minor changes in the documentation.
Those bugs were particular hard to find and fix. They appeared mostly for short looped sounds, like those commonly used in chiptunes, causing some distortion or high pitch. I was making some wrong calculations for looped sounds, which caused 1 or 2 sound frames to be skipped for each sound. For big samples, you can’t hear the difference, but for very short samples, especially looped, just 1 or 2 wrong frames can mess up the final mix, since they represent a significant part of the affected samples.
I have a lot of changes planned, but  I’m waiting for a client to  finish  his game before I go wild on the code! hehe

Download lastest czPlayer demo.

First public version of czPlayer Sound System (0.1.0)

Tuesday, December 11th, 2007

I’ve just released the first public version of czPlayer Sound System.

There are still things to improve and features to add, but a client is already using it as-is, so I chose to release it right after some documentation updates and small fixes/improvements. I have a huge list of things I want to improve, but I know myself. I’m a perfectionist, and as a result I’m never really happy with my code. So if I just kept on this cycle, I would never release it ! :)
Better release something and work from there, than to be stuck improving and never release it.

As some of you might know already. czPlayer it’s a multiplatform sound system for games. Right now it supports Windows, Windows Mobile (PocketPC/Smartphone), Symbian, and PalmOS (full ARM with prc-tools). The formats supported so far are MOD and IT for music, and WAV for sound. The next ones to come are probably ADPCM and Ogg Vorbis, but that depends on the needs of my clients, and the priority of others things left to do.

If you’re interested in a commercial license, or using it in freeware, check it out: czPlayer Sound System