bicycleguy
Well-known member
As title suggests playing wave files while displaying DemoSauce causes a crash when the '_twistyText' animation runs.
On Mac, I'm using Arduino 1.8.13, TL1.54-beta7 with PJRC T4, 320x240 display and a T3 audio board painfully converted some year ago to work on T4.
The example program 'DemoSauce' for the T4.0 has had only the .ino file modified as below to match my setup and merge WavFilePlayer so it will play the animations with music except, skipping the first occurrence of twistyText to avoid an immediate crash. The interesting spot is at //mdr309 where if you un-comment the line, sound playing is turned off for twisty and the animations will run for many minutes to hours depending on who knows what. It will eventually crash in the '_checkerboard' animation however. Longer run times with no arduino serial monitor and longer still if wall wort.
The changes from the original are commented with //mdr You should start with the T4, example DemoSauce. Then substitute the below for the DemoSauce.ino
Removed the microphone stuff and random animation selection to simplify and help debug.
Added the XPT2046_Touchscreen stuff because if I don't have its .begin() I get noise in the audio. (I don't want to unhook the touchscreen)
I'm hoping someone can try this on an T4 version(Rev D) audio board to confirm the issue.
On Mac, I'm using Arduino 1.8.13, TL1.54-beta7 with PJRC T4, 320x240 display and a T3 audio board painfully converted some year ago to work on T4.
The example program 'DemoSauce' for the T4.0 has had only the .ino file modified as below to match my setup and merge WavFilePlayer so it will play the animations with music except, skipping the first occurrence of twistyText to avoid an immediate crash. The interesting spot is at //mdr309 where if you un-comment the line, sound playing is turned off for twisty and the animations will run for many minutes to hours depending on who knows what. It will eventually crash in the '_checkerboard' animation however. Longer run times with no arduino serial monitor and longer still if wall wort.
The changes from the original are commented with //mdr You should start with the T4, example DemoSauce. Then substitute the below for the DemoSauce.ino
Removed the microphone stuff and random animation selection to simplify and help debug.
Added the XPT2046_Touchscreen stuff because if I don't have its .begin() I get noise in the audio. (I don't want to unhook the touchscreen)
Code:
/***************************************************
** DemoSauce! **
State-of-the-art graphics for your beautiful TFT display.
Greetz to the Portland Dorkbot Crew!!!!
Programmed by Zach Archer (@zkarcher) :: http://controlzinc.com/
Using hardware by Thomas Hudson (@hydronics) :: http://thomashudson.org/
Usage:
* Connect a microphone to MIC_PIN.
* Connect TFT backlight to BACKLIGHT_PIN.
MIT license, all text above must be included in any redistribution
****************************************************/
// https://github.com/zkarcher/demosauce
#include "SPI.h"
#include "ILI9341_t3.h"
#include "font_Arial.h"
#include <XPT2046_Touchscreen.h> //mdr
#include <Audio.h> //mdr
#include "FrameParams.h"
// Animations
#include "Checkerboard.h"
#include "Cube3D.h"
#include "Leaves.h"
#include "MagentaSquares.h"
//#include "MicCheck.h"
#include "PlasmaCloud.h"
#include "PlasmaYellow.h"
#include "Sphere3D.h"
#include "TriangleWeb.h"
#include "TwistyText.h"
#include "Waveform.h"
// Transitions
#include "TransitionDither.h"
#include "TransitionHalftone.h"
#include "TransitionScroll.h"
#include "TransitionSquares.h"
const boolean DO_BENCHMARKS = true;
const uint32_t SERIAL_BAUD_RATE = 9600;
const boolean DEBUG_ANIM = false; // dev: for hacking on one animation.
const uint_fast8_t DEBUG_ANIM_INDEX = 0;
const boolean DEBUG_TRANSITION = false; // dev: set to true for short animation durations
const int_fast8_t DEBUG_TRANSITION_INDEX = -1; // Supports -1: chooses a transition at random
const int_fast16_t DEFAULT_ANIM_TIME = 7.0f * 1000.0f; // ms mdr changed to 7 seconds from 20
// TFT pins
const uint8_t TFT_DC = 5; //mdr yours might be different
const uint8_t TFT_CS = 9; //mdr yours might be different
const uint8_t MIC_PIN = 14;
const uint8_t BACKLIGHT_PIN = 23;
// Use these with the Teensy Audio Shield and Teesny 4.0 mdr20190823
#define SDCARD_CS_PIN 10 //mdr yours might be different
// Pin assignment for T4 XPT2046_Touchscreen
#define T_CS_PIN 4 //mdr yours might be different
#define TIRQ_PIN 3 //mdr yours might be different
// Use hardware SPI (#13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
XPT2046_Touchscreen ts(T_CS_PIN, TIRQ_PIN); // mdr get buzzing if connected and not inialized
AudioPlaySdWav playWav1; //mdr
// Use one of these 3 output types: Digital I2S, Digital S/PDIF, or Analog DAC
AudioOutputI2S audioOutput; //mdr
AudioConnection patchCord1(playWav1, 0, audioOutput, 0); //mdr
AudioConnection patchCord2(playWav1, 1, audioOutput, 1); //mdr
AudioControlSGTL5000 sgtl5000_1; //mdr
FrameParams frameParams;
long previousMillis = 0;
Checkerboard * _checkerboard = new Checkerboard();
Cube3D * _cube3D = new Cube3D();
Leaves * _leaves = new Leaves();
MagentaSquares * _magentaSquares = new MagentaSquares();
PlasmaCloud * _plasmaCloud = new PlasmaCloud();
PlasmaYellow * _plasmaYellow = new PlasmaYellow();
Sphere3D * _sphere3D = new Sphere3D();
TriangleWeb * _triangleWeb = new TriangleWeb();
TwistyText * _twistyText = new TwistyText();
Waveform * _waveform = new Waveform();
TransitionDither * _transDither = new TransitionDither();
TransitionHalftone * _transHalftone = new TransitionHalftone();
TransitionScroll * _transScroll = new TransitionScroll();
TransitionSquares * _transSquares = new TransitionSquares();
BaseAnimation **anims; // Array of pointers to BaseAnimation's. Initialized in setup() below.
int_fast8_t animCount;
BaseAnimation *activeAnim = 0;
int_fast16_t animTimeLeft = 0;
BaseAnimation *nextAnim;
BaseTransition **transitions;
int_fast8_t transCount;
boolean isTransition = true;
BaseTransition *activeTransition = 0;
// Benchmarks
uint32_t frameCount;
// Search the anims[] aray for the activeAnim pointer. If found, return the array index.
int_fast8_t getActiveAnimIndex() {
for( int_fast8_t i=0; i<animCount; i++ ) {
if( anims[i] == activeAnim ) return i;
}
return -1; // not found
}
void setup() {
// Backlight
//pinMode( BACKLIGHT_PIN, OUTPUT ); //mdr not using
//analogWrite( BACKLIGHT_PIN, 1023 );
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(5); //mdr max seems to be 4
// Comment these out if not using the audio adaptor board.
// This may wait forever if the SDA & SCL pins lack
// pullup resistors
sgtl5000_1.enable(); //mdr
sgtl5000_1.volume(0.25); //mdr
// Microphone
pinMode( MIC_PIN, INPUT ); //mdr not using
tft.begin();
tft.setRotation( 1 );
tft.fillScreen(ILI9341_BLACK);
ts.begin(); // mdr get buzzing if connected and not inialized
ts.setRotation(2); //mdr
Serial.begin( SERIAL_BAUD_RATE );
while (!Serial && millis() < 2000)
;
// Serial
if( DO_BENCHMARKS ) {
tft.setTextColor(ILI9341_YELLOW);
tft.setFont(Arial_18);
tft.setCursor(10, 30);
tft.print("myT4_demoSauce_Audio"); //mdr changed displayed text on no serial
tft.setCursor(80, 90);
tft.print("waiting for");
tft.setCursor(60, 120);
tft.print("Serial Monitor");
tft.setTextColor(ILI9341_GREEN);
tft.setFont(Arial_18);
while (!Serial && millis() < 8000) { // wait for Arduino Serial Monitor
tft.fillRect(118, 182, 42, 18, ILI9341_BLACK);
tft.setCursor(118, 182);
tft.print((8000.0 - (float)millis()) / 1000.0, 1);
tft.print(" sec");
delay(100);
}
}
previousMillis = millis();
// Clear
uint16_t w = tft.width();
uint16_t h = tft.height();
tft.fillRect( 0, 0, w, h, 0x0 );
tft.setScroll( 0 );
// Populate anims in the order you want them to display.
BaseAnimation* ANIMS_TEMP[] = {
_twistyText,
_plasmaCloud,
_waveform,
_magentaSquares,
_sphere3D,
_checkerboard,
_leaves,
_cube3D,
_plasmaYellow,
_triangleWeb
};
animCount = sizeof( ANIMS_TEMP ) / sizeof( BaseAnimation* );
// Retain ANIMS_TEMP objects permanently
anims = (BaseAnimation**)malloc( animCount * sizeof(BaseAnimation*) );
for( int_fast8_t i=0; i<animCount; i++ ) {
anims[i] = ANIMS_TEMP[i];
anims[i]->init( tft ); // Initalize all animations
}
BaseTransition* TRANS_TEMP[] = {
_transDither,
_transHalftone,
_transScroll,
_transSquares
};
transCount = sizeof( TRANS_TEMP ) / sizeof( BaseTransition* );
// Retain TRANS_TEMP objects permanently
transitions = (BaseTransition**)malloc( transCount * sizeof(BaseTransition*) );
for( int_fast8_t i=0; i<transCount; i++ ) {
transitions[i] = TRANS_TEMP[i];
transitions[i]->init( tft );
}
// Start!
if( !activeAnim ) {
if( DEBUG_ANIM ) {
startAnimation( anims[DEBUG_ANIM_INDEX] );
} else {
startAnimation( anims[0] );
}
}
if (!(SD.begin(SDCARD_CS_PIN))) { //mdr
// stop here, but print a message repetitively
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
}
void startAnimation( BaseAnimation *newAnim ) {
isTransition = false;
activeAnim = newAnim;
tft.fillScreen( activeAnim->bgColor() );
tft.setScroll( 0 );
activeAnim->reset( tft );
animTimeLeft = DEFAULT_ANIM_TIME;
if( DEBUG_TRANSITION ) animTimeLeft = 2000;
if( DO_BENCHMARKS ) {
Serial.println("---");
Serial.print( activeAnim->title() );
if( activeAnim->willForceTransition() ) {
// TwistyText does not obey DEFAULT_ANIM_TIME
Serial.println("");
} else {
Serial.print(" [");
Serial.print( (uint8_t)(animTimeLeft / 1000.0f) );
Serial.print(" secs] AudioMemoryUsageMax "); //mdr added
Serial.println(AudioMemoryUsageMax());
}
frameCount = 0;
}
}
void loop() {
// Frame multiplier
long newMillis = millis();
uint_fast8_t elapsed = newMillis - previousMillis;
previousMillis = newMillis;
frameParams.timeMult = elapsed * (60.0f / 1000); // 1.0==exactly 60fps. 4.0==15fps, 4x slower
// Get some audio input
const uint_fast8_t SAMPLES_PER_FRAME = 1;
frameParams.audioPeak = 0;
uint_fast16_t sum = 0;
for( uint_fast8_t s=0; s<SAMPLES_PER_FRAME; s++ ) {
uint_fast16_t sample = abs( random(0,511) ); //mdr nice effects with no mic
frameParams.audioPeak = max( frameParams.audioPeak, sample );
sum += sample;
}
frameParams.audioMean = sum * (1.0 / (512*SAMPLES_PER_FRAME)); // Range: 0..1
frameParams.audioPeak = min( (uint_fast16_t)frameParams.audioPeak, (uint_fast16_t)511 );
if( !isTransition ) {
activeAnim->perFrame( tft, frameParams );
animTimeLeft -= elapsed;
if( DO_BENCHMARKS ) frameCount++;
}
// Has this animation expired?
boolean willForceTransition = activeAnim->willForceTransition();
boolean forceTransitionNow = activeAnim->forceTransitionNow();
// Debugging transitions: Ignore animations hogging the screen
if( DEBUG_TRANSITION ) willForceTransition = false;
if( !DEBUG_ANIM ) {
if( (!willForceTransition && (animTimeLeft <= 0)) || forceTransitionNow ) {
// If the transition has not started yet, then start it.
if( !isTransition ) {
isTransition = true;
nextAnim = anims[ (getActiveAnimIndex() + 1) % animCount ];
if(_twistyText==nextAnim){ //mdr309 don't play if twistyText or crash
//playWav1.stop(); //mdr un-comment this to prevent crash on twistyText
}else if(!playWav1.isPlaying()){
playWav1.play("SDTEST1.WAV"); //start playing
}
// Choose a random transition
activeTransition = transitions[ random(transCount) ];
if( DEBUG_TRANSITION && (DEBUG_TRANSITION_INDEX >= 0) ) {
activeTransition = transitions[ DEBUG_TRANSITION_INDEX ];
}
activeTransition->restart( tft, nextAnim->bgColor() );
// Benchmark: show how many frames the animation completed while alive.
if( DO_BENCHMARKS ) {
Serial.print("Frame count (more is better): ");
Serial.print( frameCount );
if( !activeAnim->willForceTransition() ) {
Serial.print( " (" );
Serial.print( (float)frameCount / (DEFAULT_ANIM_TIME / 1000.0f) );
Serial.println(" FPS)");
} else {
Serial.println("");
}
}
}
// After the transition ends, advance to the next animation
activeTransition->perFrame( tft, frameParams );
if( activeTransition->isComplete() ) {
startAnimation( nextAnim );
}
}
}
}
I'm hoping someone can try this on an T4 version(Rev D) audio board to confirm the issue.
Last edited: