Strange Sound Issue with Octobanger Project

Hey Arduino Community,

I'm working on a project called Octobanger, following the instructions on the Buttonbanger website. I'm encountering a peculiar sound problem and could really use your expertise to troubleshoot it. Here are the project details:

Project Name: Octobanger Components:

  • Arduino Uno
  • 4-channel relay shield
  • Serial MP3 player

Issue Description: As someone with limited Arduino experience, this project has been my introduction to the Arduino world. The problem I'm facing is related to sound playback. When I power up the Octobanger using DC power, it exhibits the following behavior:

  1. The first sequence is completely silent.
  2. The next sequence plays the sound as expected.
  3. It continues to cycle back and forth between silent and proper sound for subsequent sequences.

Troubleshooting Steps Taken: I've already tried several troubleshooting steps to diagnose the issue:

  1. When I power the Octobanger using USB from my PC, it works perfectly, with no sound issues.
  2. Pressing the physical reset button on the Arduino forces it into a working sound sequence.
  3. I attempted to add a jumper to the Octobanger program to activate the reset function after a sequence, hoping it would serve as a workaround. However, it seems to behave as if I've held the reset button down, causing the Octobanger to become "stuck" and unresponsive until I remove the jumper.

I'm at a loss for what might be causing this issue and how to fix it. Any advice, suggestions, or guidance you can provide would be greatly appreciated. I'm eager to learn and get this project running smoothly.

Thanks in advance for your help!

Take a look at this link: How to get the best out of this forum - Using Arduino / IDE 1.x - Arduino Forum

Forum asks for engineering facts. Words are never enough.

Lol, completely SFW. But I can see where you're coming from. Here's the site Octo Banger | (buttonbanger.com)

I'll work on pictures to help illustrate what I'm doing, I'll reply with those shortly.
I did get one more clue between posting and now. I can force it to work how I want by using a 12V 2Amp DC, and after I power the arduino, I use a jumper to connect the serial mp3 player to the 3v3 pin. It's still silent until it gets triggered for the first time. Then it works perfectly. It's a bit of a pain for startup, but at least I have it working.

The code from the Octobanger project is as follows, I haven't changed anything.

From MiniMedia.h

/*
 *  MiniMedia.h
 *
 *  A tiny class to hold properties and functions for audio/video control output.

 */

#ifndef _MINIMEDIA_H
#define _MINIMEDIA_H

#include <Arduino.h>
#include <avr/pgmspace.h>

#define MEDIA_TYPE_NONE 0X0
#define MEDIA_TYPE_CATALEX_SCARE 0X1
#define MEDIA_TYPE_CATALEX_AMB_SCARE 0X2
#define MEDIA_TYPE_SPRITE 0X03

/************catalex mp3 board constants**************************/
static int8_t Send_buf[8] = {0} ;

#define CMD_PLAY_SINGLE 0X03
#define CMD_SET_VOLUME 0X06
#define CMD_PLAY_LOOP 0X08
#define CMD_SEL_DEV 0X09
#define DEV_TF 0X02
#define CMD_STOP_PLAY 0X16
//#define CMD_PLAY_W_VOL 0X22
/*********************************************************************/

class MiniMedia
{

  public:
    MiniMedia();
    void Init(uint8_t pin, uint8_t vol, uint8_t media_type, uint8_t media_delay); 
	void PlayAmbient();
	void PlayScare();
	void Stop();
	void SetVolume(uint8_t vol); 
	void ReportConfig();
  private:
  uint8_t _transmitBitMask;
  uint8_t _volume;
  uint8_t _mediaType;
  uint8_t _mediaDelayHundreds;

  bool _init_first;
  
  volatile uint8_t *_transmitPortRegister;
  volatile uint8_t _serial_pin;
  uint16_t _tx_delay;
  // private methods
  void tx_pin_write(uint8_t pin_state);
  void write(uint8_t byte);
  // private static method for timing
  static inline void tunedDelay(uint16_t delay);
  void sendCommand(int8_t command, int16_t dat);
};


MiniMedia::MiniMedia()
{
	_init_first = false;
	_mediaType = 0x0;

}

void MiniMedia::Init(uint8_t pin, uint8_t vol, uint8_t media_type, uint8_t media_delay)
{
	_mediaType = media_type;
	_tx_delay = 238; //9600
 //_tx_delay = 239; //9600
	if(_mediaType == MEDIA_TYPE_NONE) return;
	if(!_init_first)
	{
		_serial_pin = pin;
		pinMode(_serial_pin, OUTPUT);
		digitalWrite(_serial_pin, HIGH);
		_transmitBitMask = digitalPinToBitMask(_serial_pin);
		uint8_t port = digitalPinToPort(_serial_pin);
		_transmitPortRegister = portOutputRegister(port);
		digitalWrite(_serial_pin,LOW);
		delay(500);
		if(_mediaType == MEDIA_TYPE_CATALEX_SCARE || _mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
		{
			sendCommand(CMD_SEL_DEV, DEV_TF);  //select the TF card  
			delay(500);
		}
		if(_mediaType == MEDIA_TYPE_SPRITE)
		{
			write(0x00);  //hello
			delay(500);
		}
	}
	_volume = 15; //default in case a bogus value is passed
	_mediaDelayHundreds = media_delay;
	if(_mediaType == MEDIA_TYPE_CATALEX_SCARE || _mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
	{
		if (vol != _volume && (vol > 0 && vol < 31))
			_volume = vol;
		sendCommand(CMD_SET_VOLUME, _volume); 
		delay(200);
	}
	_init_first = true;
}

void MiniMedia::ReportConfig()
{
	Serial.print(F("Media Type: "));
	switch(_mediaType)
	{
		case MEDIA_TYPE_NONE: Serial.println(F("None")); return;
		case MEDIA_TYPE_CATALEX_SCARE: Serial.println(F("Catalex Mp3 Scare Only")); break;
		case MEDIA_TYPE_CATALEX_AMB_SCARE: Serial.println(F("Catalex Mp3 Ambient + Scare")); break;
		case MEDIA_TYPE_SPRITE: Serial.println(F("Sprite Video")); break;
        default: Serial.println(F("Unknown!")); return;
	}
	Serial.print(F("Ambient Volume: "));
	Serial.println(_volume);
	if(_mediaDelayHundreds != 0)
	{
		Serial.print(F("Media Delay: "));
		Serial.println(_mediaDelayHundreds);
	}
}

void MiniMedia::SetVolume(uint8_t vol)
{
	if ((_mediaType == MEDIA_TYPE_CATALEX_SCARE || _mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
		&& vol != _volume && (vol > 0 && vol < 31))
	{
		_volume = vol;
		sendCommand(CMD_SET_VOLUME, _volume); 
		delay(100);
	}
}
void MiniMedia::PlayAmbient()
{
	if (_mediaType == MEDIA_TYPE_CATALEX_SCARE || _mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
	{
		Stop(); //added this stop() here because the Catalex was flakily looping the scare audio
		delay(20); //adding the stop and delay seems to have fixed it. MJN 20170115
		sendCommand(CMD_SET_VOLUME, _volume); //go back to ambient volume
		delay(50);
		if(_mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
			sendCommand(CMD_PLAY_LOOP, 1); //CMD_PLAY_W_INDEX loops
	}
}
void MiniMedia::PlayScare()
{
	int16_t bdata;

	if (_mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
	{
    sendCommand(CMD_SET_VOLUME, _volume); 
    delay(50);		//sendCommand(CMD_STOP_PLAY,0); //added this stop() here because the Catalex was flakily looping the scare audio
    //sendCommand(CMD_PLAY_LOOP, 2);
		//delay(30); //adding the stop and delay seems to have fixed it. MJN 20170115
		sendCommand(CMD_PLAY_SINGLE, 2);
		//20210530 MJN, reverting to old command above
		//bdata = (unsigned int)(((unsigned long)0x30 << 8) | 0x2);
		//sendCommand(CMD_PLAY_W_VOL, bdata);
   delay(10);
	}
	if (_mediaType == MEDIA_TYPE_CATALEX_SCARE)
	{
		//Stop(); //added this stop() here because the Catalex was flakily looping the scare audio
		//delay(20); //adding the stop and delay seems to have fixed it. MJN 20170115
		sendCommand(CMD_PLAY_SINGLE, 1); //we only have a scare file, so it is file 1
		//20210530 MJN, reverting to old command above
		//bdata = (unsigned int)(((unsigned long)0x30 << 8) | 0x1);
		//sendCommand(CMD_PLAY_W_VOL, bdata);
	}
	if (_mediaType == MEDIA_TYPE_SPRITE)
	{
		write(0x01);
	}
	for (int i = 0; i < _mediaDelayHundreds; i++)
		delay(10);
}
void MiniMedia::Stop()
{
	if (_mediaType == MEDIA_TYPE_CATALEX_SCARE || _mediaType == MEDIA_TYPE_CATALEX_AMB_SCARE)
		sendCommand(CMD_STOP_PLAY,0);
}
void MiniMedia::sendCommand(int8_t command, int16_t dat)
{
	if (_mediaType == MEDIA_TYPE_SPRITE) return;

	delay(20);
	Send_buf[0] = 0x7e; //
	Send_buf[1] = 0xff; //
	Send_buf[2] = 0x06; //
	Send_buf[3] = command; //
	Send_buf[4] = 0x00;//
	Send_buf[5] = (int8_t)(dat >> 8);//datah
	Send_buf[6] = (int8_t)(dat); //datal
	Send_buf[7] = 0xef; //
	for(uint8_t i=0; i<8; i++)//
	{
	write(Send_buf[i]) ;
	}
}
/* static */ 
inline void MiniMedia::tunedDelay(uint16_t delay) { 
  uint8_t tmp=0;

  asm volatile("sbiw    %0, 0x01 \n\t"
    "ldi %1, 0xFF \n\t"
    "cpi %A0, 0xFF \n\t"
    "cpc %B0, %1 \n\t"
    "brne .-10 \n\t"
    : "+r" (delay), "+a" (tmp)
    : "0" (delay)
    );
}


void MiniMedia::tx_pin_write(uint8_t pin_state)
{
  if (pin_state == LOW)
    *_transmitPortRegister &= ~_transmitBitMask;
  else
    *_transmitPortRegister |= _transmitBitMask;
}


void MiniMedia::write(uint8_t b)
{
  if (_tx_delay == 0) return;

  uint8_t oldSREG = SREG;
  cli();  // turn off interrupts for a clean txmit

  // Write the start bit
  tx_pin_write(LOW);
  tunedDelay(_tx_delay);

	for (byte mask = 0x01; mask; mask <<= 1)
	{
		if (b & mask) // choose bit
		tx_pin_write(HIGH); // send 1
		else
		tx_pin_write(LOW); // send 0
    
		tunedDelay(_tx_delay);
	}

	tx_pin_write(HIGH); // restore pin to natural state

  SREG = oldSREG; // turn interrupts back on
  tunedDelay(_tx_delay);

}



#endif // _MiniMedia_H

From PinMaps.h

/*
 * PinMaps.h
 */
#ifndef _PINMAPS_H
#define _PINMAPS_H

enum {
   DEFAULT_TTL,
   SHIELD,
   CUSTOM,
   PIN_MAP_COUNT
};

// Each TTL pin map starts with eight output pins.  The last three pins are:
//   1) Tr-in (Trigger-in) Pin
//   3) Tr-out (Trigger-out) Pin
//   4) MP-out (Media Player Serial Out) Pin 

enum {D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13};

int8_t PIN_MAPS[PIN_MAP_COUNT][11] = {
//  <------------ Output Pins ------------>  Tr-in  Tr-out  MP-out
   { D2,  D3,  D4,  D5,  D6,  D7,  D8,  D9,    D11,    D10,    D12},  // Default_TTL
   { D7,  D6,  D5,  D4,  D8,  D9, D10, D11,    A0,    A1,    A2},  // Shield 
   {  0,   0,   0,   0,   0,   0,   0,   0,    0,     0,     0}   // Custom
};

#endif // _PINMAPS_H

From OctoBanger_TTL.ino

/*
*************Octo Banger TTL*********
01/21/2017 this is a Banger with 8 channels.
Output is targeted at simple TTL for 2 of the the 4 relay modules
*** 01/22/2017 Adding frame-based state data storage per Joe AKA wickedbeernut

I am going to start by fixing FPS at 20fps, or 50ms per frame.
frame state data is going to be stored in pairs, where:
1) byte 1 represents the state byte (like always)
2) byte 2 represents the delay (in number of frames) to persist the current state
    before moving on to the next pair
The above approach will also free up another byte of eeprom that represents FPS, since
 it is now fixed.

		//20170122 MJN testing with a metronome track tonight is revealing an innacuracy in
		// the 50 ms per frame deal. Maybe a flaw with millis() or timer 0?
		//Anyway, using 49.595 below seems to make it dead on 20fps
		//changed from 49.6 to 49.595 based on this post: http://www.avrfreaks.net/forum/uno-clock-running-slow
		//user Gavin Andrews measured with a scope and found this:
		//Firstly I realised that it wasn't running fast it was running slow... If a real worldworld 60 seconds measures as 59.514 seconds Arduino time that must mean the Arduino clock is SLOW not fast.
        //They concluded that this may be a clone issue.  If this is the case, should I allow
		// for configurable compensation?
THE CONSTANT MILLIS_PER_FRAME IS NOW A FLOAT TO COMPENSATE FOR THE ABOVE.
TWEAK IF YOUR TIMING IS OFF.
09/04/2018 - K. Short:  Changed type declaration of variable "sample_ticker" from "uint8_t" to "volatile unsigned int" to ensure
                        play_sequence exits (endless looping). For example, if "hi_sample" is 150, it will wrap the variable
                        (upper bound was 254) and never exit the "while" scare sequence!
*/
#include <EEPROM.h>
#include "MiniMedia.h"
#include "PinMaps.h"

volatile float MILLIS_PER_FRAME = 50.0; //49.595; //default is 20 frames per sec (50 ms each)

volatile bool stampok = true;
volatile byte stamp_buff[5] = {8,2,0,2,6}; //holder for stamp, 8 tells PC app that we have 8 channels
// 8 = 8 channels


#define ARDUINO_LED 13 //board led
#define DEBOUNCE 5  // button debouncer, how many ms to debounce, 5+ ms is usually plenty

//eeprom offsets
//sequence data 0 - 999

const int SAMPLE_COUNT = 1000; //saving last 24 bytes for config use (total of 1024 eeprom)
//the following 2 bytes are going to be delivered with seq data
const int HI_SAMPLE_LB = 1000;
const int HI_SAMPLE_UB = 1001;

//the next 9 bytes are delivered with a config update
const int MEM_SLOTS = 9;

const int PIN_MAP_SLOT = 1002; //tells us what our pin mapping strategy is
const int TTL_TYPES_SLOT = 1003;
const int MEDIA_TYPE_SLOT = 1004;
const int MEDIA_DELAY_SLOT = 1005;
const int RESET_DELAY_SLOT = 1006; 
const int BOOT_DELAY_SLOT = 1007;
const int VOLUME_SLOT = 1008;
const int TRIGGER_TYPE_SLOT = 1009;
const int TIMING_OFFSET_TYPE_SLOT = 1010;  //some arduinos have timing issues that must be offset

//1019-1023 stamp
const int STAMP_OFFSET = 1019; //start byte of stamp

const int TTL_COUNT = 8; //number of TTL outputs
bool TTL_TYPES[TTL_COUNT] = {1,1,1,1,1,1,1,1}; //translated TTL Types
int8_t TTL_PINS[TTL_COUNT] = {2,3,4,5,6,7,8,9}; //the default
const int TRIGGER_PIN_COUNT = 3; //number of trigger pins
int8_t TRIGGER_PINS[TRIGGER_PIN_COUNT] = {11,10,12}; //stash of trigger pins and media pin
bool _had_bad_pin_map = false;
const int TIMING_OFFSET_TYPE_COUNT = 2;
const float TIMING_OFFSETS[TIMING_OFFSET_TYPE_COUNT] = {-.405,0};
const int SERIAL_WAIT = 5; //delay for serial reads

volatile uint8_t TTL_TYPE_BYTE = 0xFF;
volatile unsigned int hi_sample = 0x0;
volatile uint8_t _trigger_type = 0x1;
volatile uint8_t _pin_map = 0x0;
volatile uint8_t RESET_DELAY_SECS = 30; //default will be 30 secs I suppose
volatile byte samples[SAMPLE_COUNT]; //working buffer so we don't read from eeprom constantly
volatile uint8_t BOOT_DELAY_SECS = 0x0; //delay before the prop "goes hot"
volatile uint8_t _volume = 22;
volatile bool IS_HOT = true;
MiniMedia _Media;
volatile uint8_t _mediaType = 0x0; //0 is none
volatile uint8_t _mediaDelay = 0x0;
volatile uint8_t _timingOffsetType = 0x0;

uint8_t b;
unsigned long _triggerable_millis = 0;

void setup() 
{
  //read config from eeprom
  read_config();
  init_ouputs();
  Serial.begin(115200); //we talk to the PC at 115200
  Serial.println(F(".OBC")); //spit this back immediately tells PC what it just connected to
  _Media.Init(TRIGGER_PINS[2],_volume,_mediaType,_mediaDelay);
  _Media.PlayAmbient();
  buffer_samples();
  //blink_times(5,true); //this is a 5 second delay between the initial Serial response and later serial responses.
                  // the delay lets the PC app disconnect if it is the wrong type
  report_config();
  if(BOOT_DELAY_SECS > 0)
  {
	  Serial.println(F("Waiting for Boot Delay..."));
	  blink_times(BOOT_DELAY_SECS); //this uses 1 second per blink
  }
  delay(1000);
  Serial.println(F("Ready"));
  clear_rx_buffer();
  if(check_trigger())
  {   //this will give the user 30 seconds to upload a different config
	  //before getting stuck in an endless trigger loop.
	  Serial.println(F("Trigger detected on startup-"));
	  delay(100);
	  Serial.println(F("Going cold for 30 secs"));
	  _triggerable_millis = millis() + 30000;
  }
  else
	  _triggerable_millis = millis();
}

void init_ouputs()
{
  //init output pins
  if(_pin_map > (PIN_MAP_COUNT - 1))
  {
	_pin_map = 0; //revert to default on a bad setting
	_had_bad_pin_map = true;
  }
  //additional check, if someone sets to custom, and the custom pin buffer is not set to a 
  // legitimate pin, revert to default
  if(_pin_map > 0)
  {
	  for (int i = 0; i < TTL_COUNT; i++)
	  {
		  //allow D2 thru A7 (A6 and A7 exist on the nano)
		  if ((PIN_MAPS[_pin_map][i] < 2) || (PIN_MAPS[_pin_map][i] > A7))
		  {
				_pin_map = 0; //revert to default on a bad setting
				_had_bad_pin_map = true;
				break;
		  }
	  }
  }

  for (int i = 0; i < TTL_COUNT; i++)
  {
	  TTL_PINS[i] = PIN_MAPS[_pin_map][i];
      pinMode(TTL_PINS[i], OUTPUT);
  }
  for (int i = 0; i < TRIGGER_PIN_COUNT; i++)
  {
	  TRIGGER_PINS[i] = PIN_MAPS[_pin_map][TTL_COUNT + i];
  }
  set_ambient_out();
  pinMode(TRIGGER_PINS[0], INPUT); //init manual trigger pin
  //if we are set for ambient hi trigger, add pull-up
  if(_trigger_type == 0x1)
	  digitalWrite(TRIGGER_PINS[0], HIGH); // connect internal pull-up 
  else
	  digitalWrite(TRIGGER_PINS[0], LOW);
  pinMode(TRIGGER_PINS[1], OUTPUT);
  digitalWrite(TRIGGER_PINS[1], HIGH); // connect internal pull-up 
  pinMode(ARDUINO_LED, OUTPUT);
  digitalWrite(ARDUINO_LED, LOW);
}

bool check_trigger()
{
	if(_triggerable_millis > millis()) return false;
    //this is dumbed-down debounce check.
	//button is ussumed off at first
	//2 samples are taken for each input, separated by n milliseconds.
	//if the samples are both on, we consider it a true on condition
  static byte state1;
  static byte state2;
  state1 = digitalRead(TRIGGER_PINS[0]);   // read the button
  delay(DEBOUNCE);
  state2 = digitalRead(TRIGGER_PINS[0]);   // read the button
  if(_trigger_type == 0x0)
	  return !(state1 + state2 == 0);
  else
	  return (state1 + state2 == 0);
}
void buffer_samples()
{
  //fetch whatever eeprom values we have into buffer
  if(hi_sample > 0)
  {
	  for (int i = 0; i < SAMPLE_COUNT; i++)
	  {
		 samples[i] = EEPROM.read(i); 
	  }
  }
}

void read_config()
{
  byte dtemp = 0;
  stampok = true;
  for(int i = 0; i < 5; i++)
  {
	  dtemp = EEPROM.read(STAMP_OFFSET + i);
	  if(dtemp != stamp_buff[i])
	  {
		  stampok = false;
		  break;
	  }
  }
  
  if(stampok) //control number so we don't read in junk
  {
	  hi_sample = EEPROM.read(HI_SAMPLE_UB);   //read the high/upper byte into hi_sample
	  hi_sample = hi_sample << 8;  
	  //bitshift the high byte left 8 bits to make room for the low byte
	  hi_sample = hi_sample | EEPROM.read(HI_SAMPLE_LB); //read the low byte
	  //get reset_delay out of EEPROM, represents seconds
	  RESET_DELAY_SECS = EEPROM.read(RESET_DELAY_SLOT); 
	  BOOT_DELAY_SECS = EEPROM.read(BOOT_DELAY_SLOT);
	  TTL_TYPE_BYTE = EEPROM.read(TTL_TYPES_SLOT); 
	  _volume = EEPROM.read(VOLUME_SLOT); 
	  if(_volume < 1 || _volume > 30)
		  _volume = 15;
	  _mediaType = EEPROM.read(MEDIA_TYPE_SLOT);
	  _mediaDelay = EEPROM.read(MEDIA_DELAY_SLOT);
	  _pin_map = EEPROM.read(PIN_MAP_SLOT);
	  _trigger_type = EEPROM.read(TRIGGER_TYPE_SLOT); 
	  _timingOffsetType = EEPROM.read(TIMING_OFFSET_TYPE_SLOT);
	  for (int i = 0; i < TTL_COUNT; i++)
	  {
		TTL_TYPES[i] = bitRead(TTL_TYPE_BYTE,i); //default to TTL low Output default, active high
	  }
  }
  if(_timingOffsetType > TIMING_OFFSET_TYPE_COUNT - 1)
	  _timingOffsetType = 0x0; //cannot point to non-existent element

}
void report_config()
{
	Serial.print(F("OctoBanger TTL v"));
	for (int i = 0; i < 3; i++)
	{
        Serial.print(stamp_buff[i]);
		delay(1);
		if(i < 2) 
			Serial.print(".");
		else
			Serial.println();
	}
	if(stampok) //control number so we don't read in junk
	{
		Serial.println(F("Config OK"));
	}
	else
	{
		Serial.println(F("Config NOT FOUND, using defaults"));
	}

	Serial.print(F("Frame Count: "));
	Serial.println(hi_sample);
	float duration = 0;
	for(int i = 0; i < (hi_sample * 2); i+=2)
		duration += (float)(samples[i + 1]) * MILLIS_PER_FRAME;
	Serial.print(F("Seq Len Secs: "));
	Serial.println(duration / 1000.0);

	Serial.print(F("Reset Delay Secs: "));
	Serial.println(RESET_DELAY_SECS);
	if(BOOT_DELAY_SECS != 0)
	{
		Serial.print(F("Boot Delay Secs: "));
		Serial.println(BOOT_DELAY_SECS);
	}
	if(_had_bad_pin_map)
		Serial.println(F("Invalid custom pinmap, reset."));
	else
		Serial.print(F("Pin Map: "));
	//Serial.println(_pin_map);
	switch(_pin_map)
	{
	case 0x0: 
		Serial.println(F("Default_TTL")); break;
	case 0x1: 
		Serial.println(F("Shield")); break;
	case 0x2:
		Serial.println(F("Custom")); break;
	default: 
		Serial.println(F("Unknown")); break;
	}
	delay(300); //let serial catch its breath
	Serial.print(F("Trigger Pin in: "));
	format_pin_print(TRIGGER_PINS[0]);
	Serial.print(F("Trigger Ambient Type: "));
	if(_trigger_type == 0)
		Serial.println(F("Low (PIR or + trigger)"));
	else
		Serial.println(F("Hi (to gnd trigger)"));
	Serial.print(F("Trigger Pin Out: "));
	format_pin_print(TRIGGER_PINS[1]);
	Serial.print(F("Media Serial Pin: "));
	format_pin_print(TRIGGER_PINS[2]);

	delay(300); //let serial catch its breath

	_Media.ReportConfig();

	Serial.print(F("Timing Offset ms: "));
	Serial.println(TIMING_OFFSETS[_timingOffsetType],3);

	Serial.print(F("TTL PINS:  "));
	for (int i = 0; i < TTL_COUNT; i++)
	{
	    Serial.print(TTL_PINS[i]); 
		if(i<TTL_COUNT - 1)
			Serial.print(","); 
		else
			Serial.println();
	}
	Serial.print(F("TTL TYPES: "));
	for (int i = 0; i < TTL_COUNT; i++)
	{
	    Serial.print(TTL_TYPES[i]); 
		if(i<TTL_COUNT - 1)
			Serial.print(","); 
		else
			Serial.println();
	}

}

void format_pin_print(uint8_t inpin)
{
	if(inpin >= A0)
	{
		Serial.print("A"); 
		Serial.println((inpin - A0));
	}
	else
		Serial.println(inpin);
}

void loop()
{
	check_serial();
	if(IS_HOT)
	{
		if (check_trigger())
			play_sequence(); 
	}
}

void play_sequence()
{
	if (hi_sample == 0) return; //nothing recorded
	digitalWrite(TRIGGER_PINS[2], LOW); //trigger output pin for daisy chain
	Serial.println(F("Playing sequence..."));
    int play_sample = 0;
    _Media.PlayScare(); 
	delay(100); // .1 sec should be sufficient
	digitalWrite(TRIGGER_PINS[2], HIGH); //put back
	volatile unsigned int sample_ticker = 0;
	unsigned long start_time = millis();
	unsigned long delay_total = 0;
	float MPF_ACTUAL = MILLIS_PER_FRAME + TIMING_OFFSETS[_timingOffsetType];
	while (sample_ticker < (hi_sample * 2))
	{
		OutputTTL(samples[sample_ticker],0);
		sample_ticker++;
		delay_total += samples[sample_ticker];
		while(millis() <= (start_time + (MPF_ACTUAL * delay_total))) {}
		sample_ticker++;
	}

	if(RESET_DELAY_SECS > 0)
	{
		Serial.print(F("Waiting delay secs: "));
		Serial.println(RESET_DELAY_SECS);
	}
	set_ambient_out();
	_Media.PlayAmbient();
	blink_times(RESET_DELAY_SECS); //this uses 1 second per blink
	delay(100);
	Serial.println(F("Sequence complete, Ready"));
	clear_rx_buffer(); //this will wipe any crap that may have been transmitted in the time we were playing
}
void set_ambient_out()
{
    //set all outputs to default
	byte n = 0;
    OutputTTL(n,0);
}

//writes the bits of the current byte to our 8 TTL pins.
//It will use the usage booleans to know whether to invert
void OutputTTL(byte valIn, int offset)
{
	bool val = 0;
	for(int x = 0;x < TTL_COUNT; x++)
    {
		val = bitRead(valIn,x + offset) ^ TTL_TYPES[x];
		digitalWrite(TTL_PINS[x],val);
    }
}
void blink_alert()
{
        for (byte i = 0; i < 15; i++)
        { //blink LED 4 times when new address is received.
		  digitalWrite(ARDUINO_LED, (i & 1));
          //i & 1 will bitwise-and to 1 if i is odd, 0 if even.
          delay(100);
        }
}
void blink_once()
{
	digitalWrite(ARDUINO_LED, HIGH);
    delay(500);
	digitalWrite(ARDUINO_LED, LOW);
    delay(500);
}
void blink_times(int times)
{
	blink_times(times,false);
}
void blink_times(int times, bool with_listen)
{
	for(int i = 0; i < times; i++)
	{
		Serial.print(F("."));
		digitalWrite(ARDUINO_LED, HIGH);
		if(with_listen)check_serial(); //decided to check serial while we are blinking, as to not be "deaf"
		delay(500);
		digitalWrite(ARDUINO_LED, LOW);
		delay(500);
		if(with_listen)check_serial();
	}
	Serial.println();
}

void check_serial()
{
  //return;
  if (Serial.available() > 0) 
  {
     byte b = Serial.read();
     if (b == '@')  // command header.
     {
        delay(SERIAL_WAIT);
        if (Serial.available() > 0)
        {
          b = Serial.read();
		  delay(SERIAL_WAIT);
          switch (b)
          {
			case 'V':
			    //return version
				for (int i = 0; i < 3; i++)
				{
				  if(i < 2)
				  {
					  Serial.print(stamp_buff[i]);
					  Serial.print(".");
				  }
				  else
					  Serial.println(stamp_buff[i]);
				}
				break;
			case 'H':
			    //go hot
				IS_HOT = true;
				Serial.println(F("Ready"));
				break;
			case 'C':
			    //go cold
				IS_HOT = false;
				Serial.println(F("Standby..."));
				break;
			case 'D':
			    //download eeprom contents back to Serial
				tx_memory();
				break;
			case 'F':
			    //download just the config eeprom contents back to Serial
				tx_config();
				break;
			case 'S':
				rx_seq_data(); //here comes an Upload of seq data
				break;
		    case 'U':
				rx_controller_config(); //here comes an Upload of seq data
				break;
			case 'P': //ping back
				report_config();
				break;
            case 'T': //trigger test
				play_sequence();
				break;
            case 'M': //manual TTL state command
				b = Serial.read(); //get the state byte
				OutputTTL(b,0);
				break;  
			case 'O':
			    //is the stamp OK?
				if(stampok)
					Serial.println(F("OK"));
				else
					Serial.println(F("NO"));
				break;
			default:
				Serial.print(F("unk char:"));
				Serial.print(b);
				clear_rx_buffer();
				break;
          }
        }
     }
  }
}

//read 4 bytes from the Serial buffer and return as a 32bit integer
unsigned long SerialInt32()
{
	byte b[4];
	for(int i = 0; i < 4; i++)
	{
		while(Serial.available() == 0){}
		b[i] = Serial.read();
	}
	return (unsigned long)(((unsigned long)b[3] << 24) | ((unsigned long)b[2] << 16) | ((unsigned long)b[1] << 8) | (b[0]));
}
//read 2 bytes from the Serial buffer and return as a 16bit integer
unsigned long SerialInt16()
{
	byte b[2];
	for(int i = 0; i < 2; i++)
	{
		while(Serial.available() == 0){}
		b[i] = Serial.read();
	}
	return (unsigned int)(((unsigned long)b[1] << 8) | (b[0]));
}
void rx_seq_data()
{
	while(Serial.available() == 0){}
	unsigned int howmany = SerialInt16(); //this how many state pair bytes we are getting to read

	for(int i = 0; i < howmany && i < 1000; i++)
	{
		int waited = 0;
		while(Serial.available() == 0)
		{
			waited++;
			if(waited > 1000)
			{
				Serial.print(F("Stuck on: "));
				Serial.println(i);
				Serial.println("Upload terminated, please retry");
				return;
			}
			delay(1);
		}
		byte b = Serial.read();
   		EEPROM.write(i,b);
	}
	Serial.print(F("received "));
	Serial.print(howmany / 2);
	Serial.println(F(" frames"));
	buffer_samples(); //transfer into working buffer
	hi_sample = howmany / 2;
	EEPROM.write(HI_SAMPLE_UB, highByte(hi_sample));//writes the first byte of hi_sample
    EEPROM.write(HI_SAMPLE_LB, lowByte(hi_sample));//writes the second byte of hi_sample
	delay(300);
	float duration = 0;
	for(int i = 0; i < (hi_sample * 2); i+=2)
		duration += (float)(samples[i + 1]) * MILLIS_PER_FRAME;
	Serial.print(F("Seq Len Secs: "));
	Serial.println(duration / 1000.0);
	Serial.println(F("Saved, Ready"));
}

void rx_controller_config()
{
	while(Serial.available() == 0){}
	unsigned int howmany = SerialInt16(); //how many bytes we are getting, should be 9
	if(howmany != MEM_SLOTS)
	{
		Serial.print(F("Unknown config length passed: "));
		Serial.println(howmany);
		clear_rx_buffer();
		return;
	}

	for(int i = 0; i < howmany; i++)
	{
		int waited = 0;
		while(Serial.available() == 0)
		{
			waited++;
			if(waited > 1000)
			{
				Serial.print(F("Stuck on: "));
				Serial.println(i);
				Serial.println("Upload terminated, please retry");
				return;
			}
			delay(1);
		}
		byte b = Serial.read();
   		EEPROM.write(i + PIN_MAP_SLOT,b); //PIN_MAP_SLOT is the first byte, then they are in order
	}

	Serial.print(F("Received "));
	Serial.print(howmany);
	Serial.println(F(" config bytes"));
	Serial.println(F("Please reconnect"));
	if(!stampok)
	{
		hi_sample = 0x0;
		EEPROM.write(HI_SAMPLE_UB, highByte(hi_sample));//writes the first byte of hi_sample
		EEPROM.write(HI_SAMPLE_LB, lowByte(hi_sample));//writes the second byte of hi_sample
	}
	for(int i = 0; i < 5; i++)
		EEPROM.write(STAMP_OFFSET + i,stamp_buff[i]);
	stampok = true; //now that we have written it
	read_config();
	set_ambient_out();
    //after we do this we will disconnect to force reboot
}

void tx_memory()
{
	for(int i = 0; i < STAMP_OFFSET; i++)
	{
		byte b = EEPROM.read(i);
		Serial.write(b);
		delay(1);
	}
}
void tx_config()
{
	for(int i = PIN_MAP_SLOT; i < (PIN_MAP_SLOT + MEM_SLOTS); i++)
	{
		byte b = EEPROM.read(i);
		Serial.write(b);
		delay(1);
	}
}
void clear_rx_buffer()
{
	while(Serial.available() != 0)
	 byte b = Serial.read();
}


If these pictures are nowhere near good enough, I understand. Please let me know.



Hi, @disk1of3
Welcome to the forum.

Thanks for the images.

Can you please post a copy of your circuit a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Tom.. :grinning: :+1: :coffee: :australia:

Just wanted to come back and let anyone curious know that the solution was to use a YX5300 v1.0 serial mp3 player, the chip in the latest version is not compatible with the software.