Mercurial > hg > beaglert
diff projects/tank_wars/render.cpp @ 22:fbfeb5895efd matrix_gpio
Updated tank wars demo for new API
author | andrewm |
---|---|
date | Sun, 03 May 2015 01:10:17 +0100 |
parents | 06f93bef7dd2 |
children | 3c3a1357657d |
line wrap: on
line diff
--- a/projects/tank_wars/render.cpp Thu Apr 30 17:43:08 2015 +0100 +++ b/projects/tank_wars/render.cpp Sun May 03 01:10:17 2015 +0100 @@ -14,6 +14,8 @@ #include <cstdlib> #include <time.h> +int gAudioFramesPerMatrixFrame = 2; // Ratio in audio to matrix sample rate + int gInputTank1Angle = 0; // Inputs for the cannon angles int gInputTank2Angle = 1; int gInputLauncher = 2; // Input for launcher FSR @@ -37,8 +39,8 @@ float gLauncherFilterPole = 0.8; float gLauncherPeakValue = 0; float gLauncherPeakFilterPole = 0.999; -float gLauncherNoiseThreshold = 0.01 * MATRIX_MAX; -float gLauncherMinimumPeak = 0.1 * MATRIX_MAX; +float gLauncherNoiseThreshold = 0.01; +float gLauncherMinimumPeak = 0.1; bool gLauncherTriggered = false; // Screen update rate; affects buffer size. Actual contents of buffer @@ -61,6 +63,19 @@ // Auxiliary (low-priority) task for updating the screen AuxiliaryTask gScreenUpdateTask; +// Buffers for music and sound effects +extern float *gMusicBuffer; +extern int gMusicBufferLength; +extern float *gSoundBoomBuffer; +extern int gSoundBoomBufferLength; + +// Current state for sound and music +int gMusicBufferPointer = 0; // 0 means start of buffer... +int gSoundBoomBufferPointer = -1; // -1 means don't play... +float gSoundProjectileOscillatorPhase = 0; +float gSoundProjectileOscillatorGain = 0.2; +float gOscillatorPhaseScaler = 0; + void screen_update(); // initialise_render() is called once before the audio rendering starts. @@ -72,22 +87,26 @@ // // Return true on success; returning false halts the program. -bool initialise_render(int numMatrixChannels, int numAudioChannels, - int numMatrixFramesPerPeriod, +bool initialise_render(int numAnalogChannels, int numDigitalChannels, int numAudioChannels, + int numAnalogFramesPerPeriod, int numAudioFramesPerPeriod, - float matrixSampleRate, float audioSampleRate, + float analogSampleRate, float audioSampleRate, void *userData) { srandom(time(NULL)); // Verify we are running with matrix enabled - if(numMatrixFramesPerPeriod == 0 || numMatrixChannels < 4) { + if(numAnalogFramesPerPeriod == 0 || numAnalogChannels < 4) { rt_printf("Error: this example needs the matrix enabled with at least 4 channels\n"); return false; } + // Initialise audio variables + gAudioFramesPerMatrixFrame = numAudioFramesPerPeriod / numAnalogFramesPerPeriod; + gOscillatorPhaseScaler = 2.0 * M_PI / audioSampleRate; + // Initialise the screen buffers - gScreenBufferMaxLength = 2 * matrixSampleRate / gScreenFramesPerSecond; + gScreenBufferMaxLength = 2 * analogSampleRate / gScreenFramesPerSecond; gScreenBuffer1 = new float[gScreenBufferMaxLength]; gScreenBuffer2 = new float[gScreenBufferMaxLength]; if(gScreenBuffer1 == 0 || gScreenBuffer2 == 0) { @@ -104,7 +123,7 @@ // Initialise the game setupGame(gScreenWidth, gScreenHeight); - gGameFrameInterval = matrixSampleRate / gGameFramesPerSecond; + gGameFrameInterval = analogSampleRate / gGameFramesPerSecond; gSamplesUntilNextFrame = gGameFrameInterval; // Initialise auxiliary tasks @@ -140,12 +159,46 @@ // ADCs and DACs (if available). If only audio is available, numMatrixFrames // will be 0. -void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, - uint16_t *matrixIn, uint16_t *matrixOut) +void render(int numAnalogFrames, int numDigitalFrames, int numAudioFrames, float *audioIn, float *audioOut, + float *analogIn, float *analogOut, uint32_t *digital) { - for(int n = 0; n < numMatrixFrames; n++) { + int audioIndex = 0; + + for(int n = 0; n < numAnalogFrames; n++) { + for(int k = 0; k < gAudioFramesPerMatrixFrame; k++) { + // Render music and sound + float audioSample = 0; + + // Music plays in a loop + if(gMusicBuffer != 0 && gMusicBufferPointer >= 0) { + audioSample += gMusicBuffer[gMusicBufferPointer++]; + if(gMusicBufferPointer >= gMusicBufferLength) + gMusicBufferPointer = 0; + } + + // Sound effect plays until finished, then stops + if(gSoundBoomBuffer != 0 && gSoundBoomBufferPointer >= 0) { + audioSample += gSoundBoomBuffer[gSoundBoomBufferPointer++]; + if(gSoundBoomBufferPointer >= gSoundBoomBufferLength) + gSoundBoomBufferPointer = -1; + } + + // Oscillator plays to indicate projectile height + if(gameStatusProjectileInMotion()) { + audioSample += gSoundProjectileOscillatorGain * sinf(gSoundProjectileOscillatorPhase); + + gSoundProjectileOscillatorPhase += gOscillatorPhaseScaler * constrain(map(gameStatusProjectileHeight(), + 1.0, 0, 300, 2000), 200, 6000); + if(gSoundProjectileOscillatorPhase > 2.0 * M_PI) + gSoundProjectileOscillatorPhase -= 2.0 * M_PI; + } + + audioOut[2*audioIndex] = audioOut[2*audioIndex + 1] = audioSample; + audioIndex++; + } + // First-order lowpass filter to remove noise on launch FSR - float rawSample = analogRead(gInputLauncher, n); + float rawSample = AnalogRead(gInputLauncher, n); float launchSample = gLauncherFilterPole * gLauncherLastSample + (1.0f - gLauncherFilterPole) * rawSample; gLauncherLastSample = launchSample; @@ -164,7 +217,7 @@ // Set both cannon strengths but only one will // fire depending on whose turn it is float strength = map(gLauncherPeakValue, - gLauncherMinimumPeak, MATRIX_MAX, + gLauncherMinimumPeak, 1.0, 0.5f, 10.0f); setTank1CannonStrength(strength); setTank2CannonStrength(strength); @@ -179,11 +232,16 @@ // Update game physics and cannon angles gSamplesUntilNextFrame = gGameFrameInterval; - setTank1CannonAngle(map(analogRead(gInputTank1Angle, n), - 0, MATRIX_MAX, M_PI, 0)); - setTank2CannonAngle(map(analogRead(gInputTank2Angle, n), - 0, MATRIX_MAX, M_PI, 0)); + setTank1CannonAngle(map(AnalogRead(gInputTank1Angle, n), + 0, 1.0, M_PI, 0)); + setTank2CannonAngle(map(AnalogRead(gInputTank2Angle, n), + 0, 1.0, M_PI, 0)); nextGameFrame(); + + // Check for collision and start sound accordingly + if(gameStatusCollisionOccurred()) { + gSoundBoomBufferPointer = 0; + } } if(gScreenBufferReadPointer >= gScreenBufferReadLength - 1 @@ -199,21 +257,21 @@ // Rescale screen coordinates to matrix ranges; invert the Y // coordinate to go from normal screen coordinates to scope coordinates - analogWrite(gOutputX, n, constrain(map(x, 0, gScreenWidth, 0, MATRIX_MAX), 0, MATRIX_MAX)); - analogWrite(gOutputY, n, constrain(map(y, 0, gScreenHeight, MATRIX_MAX, 0), 0, MATRIX_MAX)); + AnalogWriteFrame(gOutputX, n, constrain(map(x, 0, gScreenWidth, 0, 1.0), 0, 1.0)); + AnalogWriteFrame(gOutputY, n, constrain(map(y, 0, gScreenHeight, 1.0, 0), 0, 1.0)); } else { // Still not ready! Write 0 until something happens - analogWrite(gOutputX, n, 0); - analogWrite(gOutputY, n, 0); + AnalogWriteFrame(gOutputX, n, 0); + AnalogWriteFrame(gOutputY, n, 0); } if(gameStatusWinner() != 0) { // Blink one LED to show who won // Blink both LEDs when projectile is in motion - uint16_t val = (gSampleCounter % 4000 > 2000) ? MATRIX_MAX : 0; - analogWrite(gOutputPlayer1LED, n, gameStatusWinner() == 1 ? val : 0); - analogWrite(gOutputPlayer2LED, n, gameStatusWinner() == 2 ? val : 0); + float val = (gSampleCounter % 4000 > 2000) ? 1.0 : 0; + AnalogWriteFrame(gOutputPlayer1LED, n, gameStatusWinner() == 1 ? val : 0); + AnalogWriteFrame(gOutputPlayer2LED, n, gameStatusWinner() == 2 ? val : 0); // After 5 seconds, restart the game gSamplesSinceFinish++; @@ -222,17 +280,17 @@ } else if(gameStatusProjectileInMotion()) { // Blink both LEDs when projectile is in motion - uint16_t val = (gSampleCounter % 2000 > 1000) ? MATRIX_MAX : 0; - analogWrite(gOutputPlayer1LED, n, val); - analogWrite(gOutputPlayer2LED, n, val); + float val = (gSampleCounter % 2000 > 1000) ? 1.0 : 0; + AnalogWriteFrame(gOutputPlayer1LED, n, val); + AnalogWriteFrame(gOutputPlayer2LED, n, val); } else if(gameStatusPlayer1Turn()) { - analogWrite(gOutputPlayer1LED, n, MATRIX_MAX); - analogWrite(gOutputPlayer2LED, n, 0); + AnalogWriteFrame(gOutputPlayer1LED, n, 1.0); + AnalogWriteFrame(gOutputPlayer2LED, n, 0); } else { - analogWrite(gOutputPlayer2LED, n, MATRIX_MAX); - analogWrite(gOutputPlayer1LED, n, 0); + AnalogWriteFrame(gOutputPlayer2LED, n, 1.0); + AnalogWriteFrame(gOutputPlayer1LED, n, 0); } // Check if we have reached the point where we should next update