Retro Invaders a space invaders clone by Chris Favreau. Written for the RetroMbuino development board from outrageouscircuits.com for the game programming contest.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sound.cpp Source File

sound.cpp

00001 #include <string.h>
00002 #include "sound.h"
00003 #include "lpc111x.h"
00004 
00005 // Useful Macros
00006 #define ISNUMBER(a) ((a >= '0') && (a <= '9'))
00007 #define ISALPHA(a) (((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z')))
00008 #define TOLOWER(a) if ((a >= 'A') && (a <= 'Z')) a = (a - 'A') + 'a';
00009 
00010 //  ======== Waveform Definitions ========
00011 // 64 elements
00012 const char sine[] = {
00013     0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
00014     0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
00015     0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
00016     0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
00017     0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
00018     0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
00019     0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
00020     0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
00021     0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
00022     0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
00023     0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
00024     0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
00025     0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
00026     0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
00027     0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
00028     0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c};
00029     
00030 const char square[] =  {
00031     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00032     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00033     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00034     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00035     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00036     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00037     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00038     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00039     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00040     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00041     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00042     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00043     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00044     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00045     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
00046     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
00047 
00048 const char sawtooth[] = {
00049     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
00050     0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
00051     0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
00052     0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
00053     0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
00054     0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
00055     0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
00056     0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
00057     0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
00058     0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
00059     0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
00060     0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
00061     0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
00062     0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
00063     0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
00064     0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff};
00065 
00066 const char triangle[] = {
00067     0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
00068     0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
00069     0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
00070     0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
00071     0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,
00072     0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,
00073     0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,
00074     0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,
00075     0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1,
00076     0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1,
00077     0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1,
00078     0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81,
00079     0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61,
00080     0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41,
00081     0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21,
00082     0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01};
00083 
00084 
00085 // For vibrato - 64 elements in length - thanks lft
00086 const int8_t sinetable[] = {
00087     0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
00088     127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
00089     0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
00090     -125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
00091     -71, -60, -49, -37, -25, -12
00092 };
00093 
00094 // -=-=-=-=-=-=-= End Waveforms -=-=-=-=-=-=-=-=-=
00095 
00096 #define PWM_FREQUENCY       23448       // 23.448 kHz => Match value of ~2047 (Convenient for binary math)
00097 #define PWM_MATCH_VAL       (48000000 / PWM_FREQUENCY)
00098 #define EFFECT_CALL_FREQ    50          // Hz
00099 #define EFFECT_CALL_WAIT    PWM_FREQUENCY / EFFECT_CALL_FREQ
00100 #define MAX_FREQ            8000                                      // 8 kHz (something pratical.. and not ear splitting)
00101 #define MAX_FREQ_INC        ((65535 * MAX_FREQ) / PWM_FREQUENCY)
00102 #define SLIDE_SCALER        ((65535 * 10) / PWM_FREQUENCY)            // 10 Hz per tick...
00103 
00104 // Volatile Interrupt Variables
00105 volatile int timer32_0_counter;
00106 Sound *pSound = NULL;
00107 volatile unsigned short int effect_wait = EFFECT_CALL_WAIT;
00108 
00109 // Interrupt ---------------------------------------
00110 
00111 void TIMER32_0_IRQHandler(void)
00112 {    
00113     // Check to see if the PWM interrupt is triggered (MR3)
00114     if (TMR32B0IR & BIT3)
00115     {
00116         if (!pSound) return;
00117         
00118         effect_wait--;
00119         if (effect_wait == 0)
00120         {
00121             // Do the effects at 50 Hz ... why because everyone does it that way
00122             pSound->DoEffects();
00123             effect_wait = EFFECT_CALL_WAIT;
00124             // Do the song at 50 Hz
00125             pSound->DoSong();
00126         }
00127         
00128         static unsigned int noiseseed = 1;
00129         unsigned char newbit;
00130         
00131         newbit = 0;
00132         if(noiseseed & 0x80000000L) newbit ^= 1;
00133         if(noiseseed & 0x01000000L) newbit ^= 1;
00134         if(noiseseed & 0x00000040L) newbit ^= 1;
00135         if(noiseseed & 0x00000200L) newbit ^= 1;
00136         noiseseed = (noiseseed << 1) | newbit;
00137         
00138         // Reset the interrupt flag
00139         TMR32B0IR = BIT3;
00140         
00141         // Increment the counter
00142         timer32_0_counter++;
00143         
00144         register int master_acc = 0;
00145         register int acc = 0;
00146         register int channels = 0;
00147         bool bMuted = pSound->bMuted;
00148         
00149         for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
00150         {
00151             SOUND_CHANNEL *pChannel = &pSound->channel[i];
00152             if ((pChannel->active) && (pChannel->volume > 0))
00153             {
00154                 pChannel->phase_acc += pChannel->phase_inc;
00155                 acc = pChannel->pWaveform[pChannel->phase_acc >> 8];    // -128 to 127
00156                 if (pChannel->use_noise) acc = (noiseseed & 0xFF) - 127;// -128 to 127
00157                 acc *= pChannel->volume;                                // 0 to 65535
00158                 acc = acc >> 8;                                         // Rescale to -128 to 127
00159                 acc += 128;                                             // 0 to 255
00160                 master_acc += acc;
00161                 channels++;
00162             }
00163         }
00164         
00165         if (channels > 1) master_acc /= channels;
00166         master_acc = master_acc << 3;                               // 0 to 2047 (PWM_MATCH_VAL)
00167         //master_acc = acc << 3;
00168         if (master_acc > PWM_MATCH_VAL) master_acc = PWM_MATCH_VAL;
00169         
00170         // Check to see if we are muted
00171         if (bMuted) master_acc = 0;
00172         
00173         // Bounds check the master accumulator
00174         TMR32B0MR0 = master_acc;  // ( xx >> 8 equivalent to x / 256)
00175     }
00176     
00177     return;
00178 }
00179 
00180 // Implementation ----------------------------------
00181 
00182 Sound::Sound()
00183 {
00184     timer32_0_counter = 0;
00185     pSound = this;
00186     for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
00187         channel[i].active = false;
00188     // Initialize the song stuff
00189     bPlaySong = false;
00190     bLoopSong = false;
00191     m_pSong = NULL;
00192     m_pSongBuffer = NULL;
00193     iSongChannel = 0;
00194     iSongNoteOffset = 0;
00195     iNoteCounter = 0;
00196     iTicksPerBeat = 0;
00197     bMuted = false;
00198 }
00199     
00200 Sound::~Sound()
00201 {
00202 }
00203 
00204 void Sound::Init()
00205 {
00206     SetupDefaults();
00207     
00208     // DISABLE the TImer
00209     TMR32B0TCR = 0;
00210     
00211     // DEBUG - do not enable the output pin so we do not make so much noise!!!
00212     // Initialize the PWM Match Output
00213     // Configure IO control register IOCON_PIO0_18 offset 0x40044048 with CT32B0_MAT0 bit set (0x02)
00214     REGISTER_32(0x40044048) = BIT1 | BIT4;
00215     
00216     // Configure the interrupt
00217     NVIC_SetVector(TIMER_32_0_IRQn, (uint32_t)TIMER32_0_IRQHandler);
00218     NVIC_SetPriority(TIMER_32_1_IRQn,0);
00219     NVIC_EnableIRQ(TIMER_32_0_IRQn);
00220     
00221     // CT32B0 base address 0x40014000
00222     // Turn ON CT32B0 => System Clock Control Register => SYSAHBCLKCTRL Bit 9
00223     SYSAHBCLKCTRL |= BIT9;
00224     // Set our frequency (counter value) in Match Register 0 (as it does not map directly to a pin) => Match Register 0 MR0
00225     TMR32B0MR3 = PWM_MATCH_VAL;        // PWM Frequency
00226     TMR32B0MR0 = 0;        // 0% Duty for now (OFF)
00227     // Configure Reset TC on Match with MR0 MR0R (Bit 1) MR0I (Bit 0) => Match Control Register MCR
00228     // Reset on Match Register 3 MR3 (as this is the register we use for the base frequency ... MR0 is used to set the duty cycle)
00229     TMR32B0MCR = BIT10 | BIT9;
00230     // PWM Control Register
00231     TMR32B0PWMC = BIT0;
00232     // Zero the counter 0 => Timer Counter Register TC
00233     TMR32B0TC = 0;
00234     // Set the PreScale Register
00235     TMR32B0PR = 0;
00236     // Clear the Prescale Counter
00237     TMR32B0PC = 0;
00238     // Enable the timer => Timer Control Register CR
00239     TMR32B0TCR = BIT0;
00240     
00241     __enable_irq();     // Enable Interrupts
00242 }
00243 
00244 void Sound::PlaySound(int iChannel, int iFreqHz, int iLength)
00245 {
00246     // Check the channel
00247     if (iChannel < 0) return;
00248     if (iChannel >= SOUND_MAX_CHANNELS) return;
00249     
00250     if (iFreqHz == 0)
00251     {
00252         StopSound(iChannel);
00253         return;
00254     }
00255     
00256     // Get a pointer to the sound channel structure
00257     SOUND_CHANNEL *pChannel = &channel[iChannel];
00258     
00259     // Calculate a phase increment value
00260     int inc = (65535 * iFreqHz) / PWM_FREQUENCY;
00261     pChannel->phase_inc = (unsigned short)inc;
00262     pChannel->orig_phase_inc = (unsigned short)inc;
00263     // Clear the phase accumulator
00264     pChannel->phase_acc = 0;
00265     
00266     // Set the play length (0 to 255, 0 = INFINITE, 1 to 255 delay in 50 Hz ticks)
00267     pChannel->play_length = iLength;
00268     
00269     // Reset the volume level to its initial setting
00270     pChannel->volume = pChannel->vol_level;
00271     
00272     // Reset the change wait to the change speed
00273     pChannel->change_wait = pChannel->change_speed;
00274     
00275     // Set the active flag last
00276     pChannel->active = true;
00277 }
00278 
00279 void Sound::StopSound(int iChannel)
00280 {
00281     // Check the channel
00282     if (iChannel < 0) return;
00283     if (iChannel >= SOUND_MAX_CHANNELS) return;
00284     
00285     // Clear the active flag
00286     channel[iChannel].active = false;
00287 }
00288 
00289 bool Sound::IsBusy(int iChannel)
00290 {
00291     // Check the channel
00292     if (iChannel < 0) return false;
00293     if (iChannel >= SOUND_MAX_CHANNELS) return false;
00294     
00295     return (channel[iChannel].active && (channel[iChannel].volume > 0));
00296 }
00297 
00298 int Sound::GetCounter(void)
00299 {
00300     return timer32_0_counter;
00301 }
00302 
00303 void Sound::SetInstrument(int iChannel, int iWaveform, int iVolume, int iDecayTime, int iSlide, int iChangeAmount, int iChangeSpeed, int iRepeatSpeed, int iVibratoDepth, int iVibratoSpeed)
00304 {
00305     // Bounds check the channel
00306     if (iChannel < 0) return;
00307     if (iChannel >= SOUND_MAX_CHANNELS) return;
00308     
00309     // Set the waveform
00310     channel[iChannel].use_noise = false;
00311     switch (iWaveform)
00312     {
00313     default:
00314     case (SOUND_SQUARE):
00315         channel[iChannel].pWaveform = (unsigned char *)square;
00316         break;
00317     case (SOUND_SAW):
00318         channel[iChannel].pWaveform = (unsigned char *)sawtooth;
00319         break;
00320     case (SOUND_TRIANGLE):
00321         channel[iChannel].pWaveform = (unsigned char *)triangle;
00322         break;
00323     case (SOUND_SINE):
00324         channel[iChannel].pWaveform = (unsigned char *)sine;
00325         break;
00326     case (SOUND_NOISE):
00327         channel[iChannel].pWaveform = (unsigned char *)square;
00328         channel[iChannel].use_noise = true;
00329         break;
00330     }
00331     
00332     // Set the volume level
00333     channel[iChannel].vol_level = iVolume;
00334     channel[iChannel].volume = iVolume;
00335     
00336     // Set the Decay time
00337     channel[iChannel].decay_amount = iDecayTime;
00338     
00339     // Set the Slide value
00340     channel[iChannel].slide = iSlide;
00341     
00342     // Set the Change Amount and Change Speed
00343     int inc = (65535 * iChangeAmount / PWM_FREQUENCY);
00344     channel[iChannel].change_inc = (signed short)inc; // frequency amount in phase increments
00345     channel[iChannel].change_speed = iChangeSpeed;                                          // change delay in 50 hz ticks
00346     channel[iChannel].change_wait = iChangeSpeed;
00347     
00348     // Set the repeat speed
00349     channel[iChannel].repeat_speed = iRepeatSpeed;  // effect repeat speed in 50 hz ticks (really a delay)
00350     channel[iChannel].repeat_wait = iRepeatSpeed;
00351     
00352     // Set the vibrato parameters
00353     channel[iChannel].vibrato_depth = iVibratoDepth;                // Vibrato amplitude
00354     channel[iChannel].vibrato_speed = iVibratoSpeed;                // Vibrato speed in 50 Hz ticks (delay)
00355     channel[iChannel].vibrato_phase = 0;
00356     channel[iChannel].vibrato_inc = 0;
00357 }
00358     
00359 // Setup the default instruments and stuff
00360 void Sound::SetupDefaults(void)
00361 {
00362     for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
00363     {
00364         // Set the default instrument parameters
00365         SetInstrument(i, SOUND_SQUARE, 255, 0, 0, 0, 0, 0, 0, 0);
00366     }
00367 }
00368 
00369 void Sound::DoEffects(void)
00370 {
00371     for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
00372     {
00373     
00374         if (!channel[i].active) continue;
00375         
00376         // Set the play length (0 to 255, 0 = INFINITE, 1 to 255 delay in 50 Hz ticks)
00377         if (channel[i].play_length > 0)
00378         {
00379             // Subtract 1 tick
00380             channel[i].play_length--;
00381             // If we get to 0 set the channel to inactive
00382             if (channel[i].play_length == 0) channel[i].active = false;
00383         }
00384     
00385         // Volume Related Effects
00386         if (channel[i].volume > 0)
00387         {
00388             short int vol = channel[i].volume;
00389             // Decay
00390             if (channel[i].decay_amount)
00391             {
00392                 if (channel[i].decay_amount < vol)
00393                     vol -= channel[i].decay_amount;
00394                 else
00395                     vol = 0;
00396             }
00397             // Set the adjusted volume level
00398             channel[i].volume = vol;
00399         }
00400         // If the volume is 0 then who cares?
00401         // Do not turn the channel off as Repeat will not work?
00402         /*
00403         if (channel[i].volume == 0)
00404         {
00405             // Turn this channel off for now
00406             channel[i].active = false;
00407         }
00408         */
00409         
00410         // Slide (Frequency Shifting) Effects
00411         if (channel[i].slide != 0)
00412         {
00413             int inc = (int)channel[i].phase_inc + ((int)channel[i].slide * SLIDE_SCALER);
00414             if ((inc > 0) && (inc < MAX_FREQ_INC))
00415                 channel[i].phase_inc = inc;
00416             else
00417                 //channel[i].active = false;
00418                 channel[i].volume = 0;
00419         }
00420         
00421         // Change (Frequency Change after Delay)
00422         if (channel[i].change_wait > 0)
00423         {
00424             channel[i].change_wait--;
00425             if (channel[i].change_wait == 0)
00426                 channel[i].phase_inc += channel[i].change_inc;
00427         }
00428         
00429         // Vibrato
00430         if (channel[i].vibrato_speed > 0)
00431         {
00432             // Calculate the vibrato waveform's phase
00433             channel[i].vibrato_phase += (channel[i].vibrato_speed * SLIDE_SCALER);
00434             // Calculate the sinewave values
00435             int inc = sinetable[channel[i].vibrato_phase & 63] * channel[i].vibrato_depth;
00436             // Rescale (from 65535 to 255)
00437             inc = inc >> 8;
00438             
00439             inc = inc + (int)channel[i].phase_inc;
00440             channel[i].phase_inc = inc;
00441         }
00442         
00443         // Repeat (resets parameters after a certain mount of time ... pew pew pew)
00444         if (channel[i].repeat_speed > 0)
00445         {
00446             channel[i].repeat_wait--;
00447             if (channel[i].repeat_wait == 0)
00448             {
00449                 // Reset the repeat wait (so we can do this again!
00450                 channel[i].repeat_wait = channel[i].repeat_speed;
00451                 // Reset the frequency and amplitude to the original
00452                 channel[i].phase_inc = channel[i].orig_phase_inc;
00453                 // Reset the volume (amplitude) to the original
00454                 channel[i].volume = channel[i].vol_level;
00455             }
00456         }
00457     }
00458 }
00459 
00460 void Sound::PlaySong(char *pRTTTL, int iChannel, int iBPM, bool bLoop)
00461 {
00462     // Check the RTTTL pointer
00463     if (!pRTTTL) return;
00464     
00465     // Stop the song temporarily
00466     bPlaySong = false;
00467     
00468     // Setup the song variables
00469     iSongChannel = iChannel;
00470     SetSongTempo(iBPM);
00471     bLoopSong = bLoop;
00472     iNoteCounter = 0;
00473     
00474     // Get the length of this song (in characters)
00475     int iNewLen = strlen(pRTTTL);
00476     
00477     // Copy and allocate the song buffer
00478     
00479     // Deal with the song buffer if it has already allocated memory
00480     if (m_pSongBuffer)
00481     {
00482         // Check to see if we need to allocate more memory
00483         if (iSongBufferLen < iNewLen)
00484         {
00485             // Cleanup the old and allocate a new buffer
00486             delete [] m_pSongBuffer;
00487             m_pSongBuffer = NULL;
00488         }
00489     }
00490     // Allocate a new song buffer if we need to
00491     if (!m_pSongBuffer)
00492     {
00493         m_pSongBuffer = new char[iNewLen + 1];
00494     }
00495     // Copy the song into the song buffer
00496     memcpy(m_pSongBuffer, pRTTTL, iNewLen);
00497     // Add an extra NULL terminator just incase
00498     m_pSongBuffer[iNewLen] = 0;
00499     
00500     // Set the song pointer to the beginning
00501     m_pSong = m_pSongBuffer;
00502     
00503     // Start the song
00504     bPlaySong = true;
00505 }
00506 
00507 #define TICKSPERMINUTE  (60 * 50)
00508 
00509 void Sound::SetSongTempo(int iBPM)
00510 {
00511     // Setup the note wait time in 50Hz ticks
00512     iTicksPerBeat = TICKSPERMINUTE / iBPM;
00513     if (iTicksPerBeat < 1) iTicksPerBeat = 1;
00514     if (iTicksPerBeat > TICKSPERMINUTE) iTicksPerBeat = TICKSPERMINUTE;
00515 }
00516 
00517 void Sound::TransposeSong(int iOffset)
00518 {
00519     iSongNoteOffset = iOffset;
00520 }
00521 
00522 void Sound::StopSong(void)
00523 {
00524     // clear the play sound
00525     bPlaySong = false;
00526     // Silence
00527     StopSound(iSongChannel);
00528     // All done with this function
00529     return;
00530 }
00531 
00532 void Sound::DoSong(void)
00533 {
00534     // Check to see if we are playing a song
00535     if (!bPlaySong) return;
00536     
00537     // Check to see if there is a song to play
00538     if (!m_pSong) return;
00539     
00540     // Check to see if we need to play the next note
00541     iNoteCounter--;
00542     if (iNoteCounter > 0) return;
00543     
00544     int duration = 4;
00545     int octave = 5;
00546     int freq = NOTE_C4;
00547     char note = 'c';
00548     bool bSharp = false;
00549     bool bDotted = false;
00550     int volume = channel[iSongChannel].volume;
00551     while (*m_pSong != ',')
00552     {
00553         // Parse and play a note
00554         // Check for duration
00555         if (ISNUMBER(*m_pSong))
00556         {
00557             duration = *m_pSong - '0';
00558             m_pSong++;
00559             if (ISNUMBER(*m_pSong))
00560             {
00561                 duration = (duration * 10) + (*m_pSong - '0');
00562                 m_pSong++;
00563             }
00564         }
00565         // Check for the note
00566         if (ISALPHA(*m_pSong))
00567         {
00568             TOLOWER(*m_pSong);
00569             note = *m_pSong;
00570             m_pSong++;
00571         }
00572         // Check for a sharp
00573         if (*m_pSong == '#') { bSharp = true; m_pSong++; }
00574         // Check for dotted
00575         if (*m_pSong == '.') { bDotted = true; m_pSong++; }
00576         // Check for the octave
00577         if (ISNUMBER(*m_pSong))
00578         {
00579             octave = *m_pSong - '0';
00580             m_pSong++;
00581         }
00582         // Check to see if we need to start over
00583         if (*m_pSong == 0)
00584         {  
00585             if (bLoopSong)
00586             {
00587                 // Set the song buffer to the beginning
00588                 m_pSong = m_pSongBuffer;
00589                 // and process the first note all over again
00590                 continue;
00591             }
00592             else
00593             {
00594                 StopSong();
00595                 // All done with this function
00596                 return;
00597             }
00598         }
00599         // Next character so we do not get stuck
00600         if (*m_pSong != ',') m_pSong++;
00601         // Check for silence
00602         if (note != 'p')
00603         {
00604             // Convert the note to a frequency
00605             freq = SongGetFreq(note, octave, bSharp);
00606             // Play the note
00607             PlaySound(iSongChannel, freq, volume + 1);
00608         }
00609         else
00610         {
00611             // Silence (Pause)
00612             StopSound(iSongChannel);
00613         }
00614         
00615         // Set the note counter so we play the note for so many frames
00616         switch(duration)
00617         {
00618         case (1): iNoteCounter = 4 * iTicksPerBeat; break;
00619         case (2): iNoteCounter = 2 * iTicksPerBeat; break;
00620         default:
00621         case (4): iNoteCounter = iTicksPerBeat; break;
00622         case (8): iNoteCounter = iTicksPerBeat >> 1; break;
00623         case (16): iNoteCounter = iTicksPerBeat >> 2; break;
00624         case (32): iNoteCounter = iTicksPerBeat >> 3; break;
00625         }
00626         if (bDotted) iNoteCounter += iNoteCounter >> 1;
00627         
00628         //char cTemp[32];
00629         //snprintf(cTemp, 32, "N(%c%c)D(%02d)O(%d)", note, bSharp ? '#' : ' ', duration, octave);
00630         //disp.drawString(0, 16, cTemp, DisplayN18::RED, DisplayN18::BLACK);
00631 
00632     }
00633     m_pSong++;
00634 }
00635 
00636 int Sound::SongGetFreq(char note, int octave, bool bSharp)
00637 {
00638     // Bounds check the octave
00639     if (octave < 4) octave = 4;
00640     if (octave > 6) octave = 6;
00641     
00642     switch(octave)
00643     {
00644     case (4):
00645         switch(note)
00646         {
00647         case ('a'):
00648             if (bSharp) return NOTE_As4;
00649             return NOTE_A4;
00650         case ('b'):
00651             if (bSharp) return NOTE_C5;
00652             return NOTE_B4;
00653         case ('c'):
00654             if (bSharp) return NOTE_Cs4;
00655             return NOTE_C4;
00656         case ('d'):
00657             if (bSharp) return NOTE_Ds4;
00658             return NOTE_D4;
00659         case ('e'):
00660             if (bSharp) return NOTE_F4;
00661             return NOTE_E4;
00662         case ('f'):
00663             if (bSharp) return NOTE_Fs4;
00664             return NOTE_F4;
00665         case ('g'):
00666             if (bSharp) return NOTE_Gs4;
00667             return NOTE_G4;
00668         }
00669     case (5):
00670         switch(note)
00671         {
00672         case ('a'):
00673             if (bSharp) return NOTE_As5;
00674             return NOTE_A5;
00675         case ('b'):
00676             if (bSharp) return NOTE_C6;
00677             return NOTE_B5;
00678         case ('c'):
00679             if (bSharp) return NOTE_Cs5;
00680             return NOTE_C5;
00681         case ('d'):
00682             if (bSharp) return NOTE_Ds5;
00683             return NOTE_D5;
00684         case ('e'):
00685             if (bSharp) return NOTE_F5;
00686             return NOTE_E5;
00687         case ('f'):
00688             if (bSharp) return NOTE_Fs5;
00689             return NOTE_F5;
00690         case ('g'):
00691             if (bSharp) return NOTE_Gs5;
00692             return NOTE_G5;
00693         }
00694     case (6):
00695         switch(note)
00696         {
00697         case ('a'):
00698             if (bSharp) return NOTE_As6;
00699             return NOTE_A6;
00700         case ('b'):
00701             if (bSharp) return NOTE_C7;
00702             return NOTE_B6;
00703         case ('c'):
00704             if (bSharp) return NOTE_Cs6;
00705             return NOTE_C6;
00706         case ('d'):
00707             if (bSharp) return NOTE_Ds6;
00708             return NOTE_D6;
00709         case ('e'):
00710             if (bSharp) return NOTE_F6;
00711             return NOTE_E6;
00712         case ('f'):
00713             if (bSharp) return NOTE_Fs6;
00714             return NOTE_F6;
00715         case ('g'):
00716             if (bSharp) return NOTE_Gs6;
00717             return NOTE_G6;
00718         }
00719     }
00720     
00721     return NOTE_C7;
00722 }
00723 
00724 void Sound:: Mute(bool mute)
00725 {
00726     bMuted = mute;   
00727 }