![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Invaders game for the Gameduino
Diff: utils.h
- Revision:
- 2:20a89dc286d5
- Parent:
- 1:f44175dd69fd
diff -r f44175dd69fd -r 20a89dc286d5 utils.h --- a/utils.h Sat Sep 29 13:01:42 2012 +0000 +++ b/utils.h Thu Dec 20 21:33:52 2012 +0000 @@ -1,232 +1,232 @@ -#ifndef COM_ARTLUM_GDUTILS_INCLUDED -#define COM_ARTLUM_GDUTILS_INCLUDED -#include "arduino.h" -#include "GD.h" -//#include "WProgram.h" - -/*--------------------------------------------------- - Coprocessor controller - makes it easy to do - raster effects (eg. split screens) without - writing any FORTH. - - The way this works is that you build a list of - instructions in memory (a "copperlist") and - the coprocessor will execute the list on every - video frame. - - Code samples: - - void setup() { - ... - // Make a copperlist to change a palette color on line 100 - // The copperlist is stored on the Gameduino at address 0x3f80 - Coprocessor::reset(); - CopperlistBuilder cp; - cp.begin(0x3f80); - cp.wait(100); - cp.write16(PALETTE4A, 0x7fff); - cp.end(); // And start using the new copperlist - } - - Modifying an existing copperlist: - - // Make a copperlist to set the horizontal scroll register - // on line 220 and modify the copperlist. - // a) Build the list - unsigned int XscrollInst; - void setup() { - ... - CopperlistBuilder cp; - cp.begin(0x3f80); - cp.wait(220); - XscrollInst = cp.position(); // Get current output location - cp.write16(SCROLL_X, 0); - cp.end(); - } - // b) Modify the list with current 'xscroll' - void loop() { - CopperlistBuilder cp; - cp.begin(XscrollInst) // Where the 'write16()' instruction is - cp.write16(SCROLL_X, xscroll); // Overwrite the previous instruction - } - - Notes: - The Coprocessor object uses the "COMM" block - of memory at 0x2980 so don't mess with it. - - The coprocessor also provides support for the - sound functions below. ----------------------------------------------------*/ -class Coprocessor { -public: - // This initializes everything and load the coprocessor code. - // You should call this in your setup() function after "GD.begin();" - // - // The sample page is the page of Gameduino memory to - // use as a buffer for sample playback. It *must* be - // on a page boundry (ie. bottom 8 bits are 0) and - // the whole page will be used so you can't use it - // for anything else. - static void reset(unsigned int samplePage=0x3f00); // Default: Use memory from 0x3f00 to 0x3fff - - // Select a copperlist. The list will start running on the next video frame. - // nb. The "CopperlistBuilder::end()" function normally calls this automatically - // (unless you tell it not to...) - static void setCopperlist(unsigned int addr); - - // Where the sample playback page is located - static unsigned int samplePage(); - - // Where the coprocessor is currently reading samples - // from in the sample page. Use this info to keep the - // page full of fresh sample data for playback - static byte sampleReadPos(); - - // A copy of the coprocessor YLINE register - static int yline(); -}; - -// This object helps you make a copperlist in memory -class CopperlistBuilder { - unsigned int out,start; - void put(byte); - void put16(unsigned int); -public: - // Available commands are: - // * Wait for a raster line - // * Write a byte to a memory location - // * Write a 16-bit word to a memory location - // * Copy a block of memory from one place to another - void begin(unsigned int dest); - void wait(int line); - void write(unsigned int addr, byte val); - void write16(unsigned int addr, unsigned int val); - void copy(unsigned int src, unsigned int dst, unsigned int numBytes); - void end(bool executeNow=true); - - // Where I'm currently outputting - unsigned int position(); -}; - - -/*------------------------------------------------------------------ - Sound functions - play synthesized sounds and sound samples - - These functions require support from the Coprocessor object - above. If you load different microcode they'll stop working... -------------------------------------------------------------------*/ - -/*------------------------------------------------------------------ - Synthesized sounds -------------------------------------------------------------------*/ -#define SYNTHSOUNDS 0 -#if SYNTHSOUNDS -// ADSR volume envelope -struct ADSR { - byte attack; // Attack time (in clock ticks) - byte decay; // Decay time (in clock ticks) - byte sustain; // Sustain level [0..255] - byte release; // Release time (in clock ticks) - ADSR(byte a=4, byte d=4, byte s=90, byte r=30); - byte evaluate(unsigned int elapsedTime, unsigned int releaseTime); -}; - -// Change pitch of a sound as it plays -struct PitchModulator { - // Vibrato - byte vibratoDelay; // Delay before vibrato starts (in clock ticks) - byte vibrato; // Amount of vibrato (percentage of note pitch) - char vibratoDelta; // Added to 'vibrato' every clock tick - // Pitch Sweep - byte sweepDelay; // Delay before sweep starts (in clock ticks) - byte sweep; - char sweepDelta; - PitchModulator() { - vibratoDelay = 0; - vibrato = 0; - vibratoDelta = 0; - } - int evaluate(int startpitch, unsigned int time); -}; - -// All the parameters for a sound -struct Sound { - ADSR adsr; - PitchModulator pm; -}; - -class SoundPlayer { - // Playback parameters - Sound sound; - byte volume; - unsigned int pitch; - unsigned int duration; - // Internal vars - unsigned int ticks; - bool active, releasing; - // Sound players form a linked list - bool isLinked; - SoundPlayer *link; - // The SoundPlayer is updated from SoundController - void update(); - friend class SoundController; - // You can't copy me... - SoundPlayer(const SoundPlayer&); - void operator=(const SoundPlayer&); -public: - SoundPlayer(); - - // Set the sound parameters - SoundPlayer& setSound(const Sound&); - - // Set playback volume in range [0..255], default = 255 - SoundPlayer& setVolume(byte); - - // Play a sound, pitch in Hz, duration in clock ticks. - // If duration is 'infinite' then the sound plays until you call 'release()' - // One "clock tick" is equivalent to one call to "SoundController::update()" - enum { infinite=0x7fff }; - void play(unsigned int pitchHz, unsigned int duration=infinite); - - // Make the current sound enter the 'release' phase - void release(); - - // Stop sound playback immediately - void stop(); -}; -#endif - -/*------------------------------------------------------------------ - Main sound controller object -------------------------------------------------------------------*/ -struct SoundController { - // Reset all sounds, return to silence - static void reset(); - - // Update all sound - call this at least once every video frame. - // The frequency at which you call this function is one "clock tick" for synthesised sounds - static void update(); - - // Play a sound sample from program memory - // Samples are eight bits and will be played at - // the system sample rate (see "Coprocessor"). - // if "numBytes" is negative, the sample will repeat until you play - // another sample on the channel (eg. pass a null pointer to "playSample()"...) - static void playSample(prog_char*, int numBytes, byte channel); -}; - - - -/*------------------------------------------------------------ - Useful little functions -------------------------------------------------------------*/ -// Show a number on screen -void showNumber(int n, byte x, byte y); -void showHexNumber(unsigned int n, byte x, byte y); - -// Send screenshot to serial port - -void sendScreenshot(); - -// COM_ARTLUM_GDUTILS_INCLUDED -#endif +#ifndef COM_ARTLUM_GDUTILS_INCLUDED +#define COM_ARTLUM_GDUTILS_INCLUDED +#include "arduino.h" +#include "GD.h" +//#include "WProgram.h" + +/*--------------------------------------------------- + Coprocessor controller - makes it easy to do + raster effects (eg. split screens) without + writing any FORTH. + + The way this works is that you build a list of + instructions in memory (a "copperlist") and + the coprocessor will execute the list on every + video frame. + + Code samples: + + void setup() { + ... + // Make a copperlist to change a palette color on line 100 + // The copperlist is stored on the Gameduino at address 0x3f80 + Coprocessor::reset(); + CopperlistBuilder cp; + cp.begin(0x3f80); + cp.wait(100); + cp.write16(PALETTE4A, 0x7fff); + cp.end(); // And start using the new copperlist + } + + Modifying an existing copperlist: + + // Make a copperlist to set the horizontal scroll register + // on line 220 and modify the copperlist. + // a) Build the list + unsigned int XscrollInst; + void setup() { + ... + CopperlistBuilder cp; + cp.begin(0x3f80); + cp.wait(220); + XscrollInst = cp.position(); // Get current output location + cp.write16(SCROLL_X, 0); + cp.end(); + } + // b) Modify the list with current 'xscroll' + void loop() { + CopperlistBuilder cp; + cp.begin(XscrollInst) // Where the 'write16()' instruction is + cp.write16(SCROLL_X, xscroll); // Overwrite the previous instruction + } + + Notes: + The Coprocessor object uses the "COMM" block + of memory at 0x2980 so don't mess with it. + + The coprocessor also provides support for the + sound functions below. +---------------------------------------------------*/ +class Coprocessor { +public: + // This initializes everything and load the coprocessor code. + // You should call this in your setup() function after "GD.begin();" + // + // The sample page is the page of Gameduino memory to + // use as a buffer for sample playback. It *must* be + // on a page boundry (ie. bottom 8 bits are 0) and + // the whole page will be used so you can't use it + // for anything else. + static void reset(unsigned int samplePage=0x3f00); // Default: Use memory from 0x3f00 to 0x3fff + + // Select a copperlist. The list will start running on the next video frame. + // nb. The "CopperlistBuilder::end()" function normally calls this automatically + // (unless you tell it not to...) + static void setCopperlist(unsigned int addr); + + // Where the sample playback page is located + static unsigned int samplePage(); + + // Where the coprocessor is currently reading samples + // from in the sample page. Use this info to keep the + // page full of fresh sample data for playback + static byte sampleReadPos(); + + // A copy of the coprocessor YLINE register + static int yline(); +}; + +// This object helps you make a copperlist in memory +class CopperlistBuilder { + unsigned int out,start; + void put(byte); + void put16(unsigned int); +public: + // Available commands are: + // * Wait for a raster line + // * Write a byte to a memory location + // * Write a 16-bit word to a memory location + // * Copy a block of memory from one place to another + void begin(unsigned int dest); + void wait(int line); + void write(unsigned int addr, byte val); + void write16(unsigned int addr, unsigned int val); + void copy(unsigned int src, unsigned int dst, unsigned int numBytes); + void end(bool executeNow=true); + + // Where I'm currently outputting + unsigned int position(); +}; + + +/*------------------------------------------------------------------ + Sound functions - play synthesized sounds and sound samples + + These functions require support from the Coprocessor object + above. If you load different microcode they'll stop working... +------------------------------------------------------------------*/ + +/*------------------------------------------------------------------ + Synthesized sounds +------------------------------------------------------------------*/ +#define SYNTHSOUNDS 0 +#if SYNTHSOUNDS +// ADSR volume envelope +struct ADSR { + byte attack; // Attack time (in clock ticks) + byte decay; // Decay time (in clock ticks) + byte sustain; // Sustain level [0..255] + byte release; // Release time (in clock ticks) + ADSR(byte a=4, byte d=4, byte s=90, byte r=30); + byte evaluate(unsigned int elapsedTime, unsigned int releaseTime); +}; + +// Change pitch of a sound as it plays +struct PitchModulator { + // Vibrato + byte vibratoDelay; // Delay before vibrato starts (in clock ticks) + byte vibrato; // Amount of vibrato (percentage of note pitch) + char vibratoDelta; // Added to 'vibrato' every clock tick + // Pitch Sweep + byte sweepDelay; // Delay before sweep starts (in clock ticks) + byte sweep; + char sweepDelta; + PitchModulator() { + vibratoDelay = 0; + vibrato = 0; + vibratoDelta = 0; + } + int evaluate(int startpitch, unsigned int time); +}; + +// All the parameters for a sound +struct Sound { + ADSR adsr; + PitchModulator pm; +}; + +class SoundPlayer { + // Playback parameters + Sound sound; + byte volume; + unsigned int pitch; + unsigned int duration; + // Internal vars + unsigned int ticks; + bool active, releasing; + // Sound players form a linked list + bool isLinked; + SoundPlayer *link; + // The SoundPlayer is updated from SoundController + void update(); + friend class SoundController; + // You can't copy me... + SoundPlayer(const SoundPlayer&); + void operator=(const SoundPlayer&); +public: + SoundPlayer(); + + // Set the sound parameters + SoundPlayer& setSound(const Sound&); + + // Set playback volume in range [0..255], default = 255 + SoundPlayer& setVolume(byte); + + // Play a sound, pitch in Hz, duration in clock ticks. + // If duration is 'infinite' then the sound plays until you call 'release()' + // One "clock tick" is equivalent to one call to "SoundController::update()" + enum { infinite=0x7fff }; + void play(unsigned int pitchHz, unsigned int duration=infinite); + + // Make the current sound enter the 'release' phase + void release(); + + // Stop sound playback immediately + void stop(); +}; +#endif + +/*------------------------------------------------------------------ + Main sound controller object +------------------------------------------------------------------*/ +struct SoundController { + // Reset all sounds, return to silence + static void reset(); + + // Update all sound - call this at least once every video frame. + // The frequency at which you call this function is one "clock tick" for synthesised sounds + static void update(); + + // Play a sound sample from program memory + // Samples are eight bits and will be played at + // the system sample rate (see "Coprocessor"). + // if "numBytes" is negative, the sample will repeat until you play + // another sample on the channel (eg. pass a null pointer to "playSample()"...) + static void playSample(prog_char*, int numBytes, byte channel); +}; + + + +/*------------------------------------------------------------ + Useful little functions +------------------------------------------------------------*/ +// Show a number on screen +void showNumber(int n, byte x, byte y); +void showHexNumber(unsigned int n, byte x, byte y); + +// Send screenshot to serial port + +void sendScreenshot(); + +// COM_ARTLUM_GDUTILS_INCLUDED +#endif