Retro Invaders a space invaders clone by Chris Favreau. Written for the RetroMbuino development board from outrageouscircuits.com for the game programming contest.
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 }
Generated on Thu Jul 14 2022 20:06:44 by 1.7.2