Need help using adafruit Music Maker shield with arduino Uno

Posted this over on the adafruit forums, but I was basically already told that I'm on my own, so I thought I'd turn to a few more places.

I'm really hoping someone here can tell me what we need to do with the output values from the mic to make them readable by the mp3/wav/ogg/etc codec player.

since I posted this elsewhere first, I may have forgotten something important. Just let me know if there's anything else that's needed.

Before I get started, the hardware setup I have is the hardware setup I'm keeping. I don't want to use a weaker shield than what I have just to make it easy to copy/paste code and get a working board that can only play wav files, needs an extra amplifier, and only supports mono.

alright, so we worked on this all weekend, and here's where we are at. I'm hoping some more specific questions might be answerable.

We plug in the mic, and start serial printing the readings. We get readings around 300 when silent, and around 700 when the mic reads loud noises. So, next we began writing that to a buffer, splitting the bits the same way the inbuilt functions do (you'll see that in the code), and then we call the playdata function, and we get silence. We did confirm that our loops are getting through the play data function, but we figured maybe the board doesn't know to start playing audio, since all of the filetypes it support would be telling the board what to do by reading a file header.

So, from that point, we tried 2 things. First, we tried making our own wav file header and sending it to the board in front of our data. That didn't work (and we think we made a mistake there by only calling playdata once, which wouldn't complete sending the 44 bit file header) but we tried something else that should have if that was going to work. We tried starting track001.wav, and then switching the stream over to the microphone. Again, we are getting numbers in our buffer and it's filling properly, but no sound from the speakers (not even "wrong" sound). We tried that second method because we know track001.wav has a proper file header (since it does in fact play) but again, switching the buffer produced no sound.

Stumbled across this, but we were having trouble implementing it. GitHub - TMRh20/TMRpcm: Arduino library for asynchronous playback of PCM/WAV files direct from SD card. Arduino Uno,Nano,Mega etc supported

We also tried forcing it to read hard Fs (hex) so that it would be the loudest possible signal and nothing. again, our buffers were correctly filled, but no audio is coming from the board.

So, any tips? something we formatted improperly? functions we are improperly calling? Help from here would be greatly appreciated.

Also, to the best of our understanding, the record to ogg function is totally useless to us. We are understanding it that the img file partially flashes the rom of the board and since it handles all of the definitions in that img file, we can't change anything about the way it records or writes ourselves.

/*************************************************** 
 * This is an example for the Adafruit VS1053 Codec Breakout
 * Designed specifically to work with the Adafruit VS1053 Codec Breakout 
 * ----> https://www.adafruit.com/products/1381
 * 
 * Adafruit invests time and resources providing this open source code, 
 * please support Adafruit and open-source hardware by purchasing 
 * products from Adafruit!
 * 
 * Written by Limor Fried/Ladyada for Adafruit Industries.  
 * BSD license, all text above must be included in any redistribution
 ****************************************************/

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include "Button.h"
#include "ZPlayer.h"
//#include "MomentaryButton.h"


// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

ZPlayer musicPlayer = 
// create breakout-example object!
//Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
// create shield-example object!
ZPlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
int lVolume=20;
int rVolume=20;
int Volume=20;
int inPin[4] = {
  A1, 5, A2, A5};

int counterA = 0;       // how many times we have seen new value  
int counterB = 0;
int counterC = 0;
int counterD = 0;
int reading[4];
int lastStateD = 0;

int MAXVOLUME = 100;
int MaxTrack = 2;
int state[4] = {
  HIGH, HIGH, HIGH, HIGH};

long timeA = 0;
long timeB = 0;
long timeC = 0;
long timeD = 0;
int debounce_count =2;
//int i=0;
////

//char tracks[2][13] = { //The first number is the number of tracks. 12 Character names + null terminator.
// "track001.mp3",
// "track002.mp3",
//}

Button buttonA(A1);
Button buttonB(5);
Button buttonC(A2);
Button buttonD(A5);

uint16_t aBuffer[16];
uint8_t dBuffer[32];

void setup() {

  //pinMode(inPin[0], INPUT_PULLUP);
  //pinMode(inPin[1], INPUT_PULLUP);
  //pinMode(inPin[2], INPUT_PULLUP);
  //pinMode(inPin[3], INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("Adafruit VS1053 Library Test");

  // initialise the music player
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));

  //musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }
  Serial.println("SD OK!");

  // list files
  printDirectory(SD.open("/"), 0);

  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(lVolume,rVolume);

  /***** Two interrupt options! *******/
  // This option uses timer0, this means timer1 & t2 are not required
  // (so you can use 'em for Servos, etc) BUT millis() can lose time
  // since we're hitchhiking on top of the millis() tracker
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);

  // This option uses a pin interrupt. No timers required! But DREQ
  // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
  // that's Digital #2 or #3
  // See http://arduino.cc/en/Reference/attachInterrupt for other pins
  // *** This method is preferred
  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));
}

void loop() {
 Serial.println("Started Loop");
/*
 uint8_t header[44] = {
 'R' , 'I' , 'F' , 'F' , 
 0x20, 0x20, 0x20, 0x20,
 'W' , 'A' , 'V' , 'E' ,
 'f' , 'm' , 't' , 0x20,
 0x0F, 0x00, 0x00, 0x00,
 0x01, 0x00,
 0x01, 0x00,
 0x44, 0xAC, 
 0x00, 0x00,
 0x44, 0xAC, 
 0x00, 0x00,
 0x01, 0x00, 
 0x08, 0x00,
 'd' , 'a' , 't' , 'a' ,
 0x20, 0x20, 0x20, 0x20,
 };
*/

  musicPlayer.playData(header, 44);
  

  while(true) {
     if(!musicPlayer.started) {
     if(!musicPlayer.startFile("track001.wav")) {
     break;
     }
 musicPlayer.play();
 musicPlayer.play();
     }
 
    // VolumeControl();
    // if(queryButton(3)) {
    // handleInput();

    // if(musicPlayer.playingMusic) {
    // musicPlayer.play();
    // }

    while(!musicPlayer.readyForData());

    for(uint16_t i = 0; i < 16; i++) {
      aBuffer[i] = analogRead(0);
      //aBuffer[i] = 0xFFFF;
      //Serial.println(aBuffer[i]);
    }
    Serial.print("A:{ ");
    for(int i = 0; i < 16; i++) {
      Serial.print(aBuffer[i], HEX);
      Serial.print("  ");
    }
    Serial.print("}");
    Serial.print("\n");
    for (uint16_t i = 0; i < 16; i++) {
      uint16_t t = aBuffer[i];
      dBuffer[i * 2] = t & 0xFF; 
      dBuffer[(i * 2) + 1] = (t >> 8) & 0xFF;
    }
    Serial.print("D:{ ");
    for(int i = 0; i < 32; i += 2) {
      Serial.print(dBuffer[i], HEX);
      Serial.print(" ");
      Serial.print(dBuffer[i+1], HEX);
      Serial.print(" ");
    }
    Serial.print("}");
    Serial.print("\n");
    musicPlayer.playData(dBuffer, 32);
  
  }
}

void handleInput() {
  //Play / Pause
  if(buttonD.pressed()) {
    if(!musicPlayer.playingMusic) {
      musicPlayer.playingMusic = true; //Unpause
    }
    else {
      musicPlayer.playingMusic = false; //Pause
      Serial.println("Paused.");
    }
  }

  //Volume
  if (buttonA.pressed()) { //A
    VolumeDown();
    Serial.println("Changing Volume");
    Serial.print("Volume is now set to: ");
    Serial.println(lVolume);
    musicPlayer.setVolume(lVolume,rVolume);
  }

  timeB = millis();

  if (buttonB.pressed()) { //B
    VolumeUp();
    Serial.println("Changing Volume");
    Serial.print("Volume is now set to: ");
    Serial.println(lVolume);
    musicPlayer.setVolume(lVolume,rVolume);
  }

  //Skip

}

boolean queryButton(int n) { //Checks the state of a given button
  int read = digitalRead(inPin[n]); //Read the physical pin

  if(read != state[n]) { //If the state has changed
    state[n] = read; //Store the new state
    if (state[n] == LOW) { //If the state is high
      return true; //Yes, the button is being pressed
    }
    return false; //Nope
  }
  return false; //Nope
}

void VolumeDown(){
  int MAX = MAXVOLUME;
  int MIN = 1;

  if( Volume < MAX){ //Lower Volume
    //Volume++;
    Volume = Volume +5; //use this to increase by a number other than 1
    lVolume = Volume;
    rVolume = Volume;
  }
} 

void VolumeUp(){
  int MAX = MAXVOLUME;
  int MIN = 1;

  if(Volume > MIN) {//&& Volume <= MAX){ //Raise health
    //Volume--;
    Volume = Volume -5; //use this to increase by a number other than 1
    lVolume = Volume;
    rVolume = Volume;
  }
}

//void NextTrack(){  
//   timeB = millis();  
// readingB = digitalRead(inPinB);
//if(readingB != current_stateB)
//{
//current_stateB = readingB;
//if (current_stateB == HIGH)
//{
//VolumeUp();
//Serial.println("Changing Volume");
//Serial.print("Volume is now set to: ");
//Serial.println(lVolume);
//musicPlayer.stopPlaying() ;
//}
//}    
//timeB = millis()

//}

/// File listing helper
void printDirectory(File dir, int numTabs) {
  while(true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i=0; i<numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs+1);
    } 
    else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

and buttonh (which I don't believe is in use right now)

class Button {
	private:
		int pin;
		int pstate;
		int time;
		
	public:
		int state() {
			if (pressed()) {
				if (time > HOLD) {
					return HELD;
				}
				return DOWN;
			}
			return UP;
		}
		
		Button(int in) {
			pin = in;
			pinMode(pin, INPUT_PULLUP);
			
			pstate = HIGH;
			time = 0;
		}
		
		boolean pressed() {
			int read = digitalRead(pin);	//Read the physical pin
			if(read != pstate) {				//If the state has changed
				pstate = read;				//Store the new state

				if (pstate == LOW) {			//If the state is high
					Serial.println("stuff");
                                        return true;				//Yes, the button is being pressed
                                }
				time = 0;
				return false;					//Nope
			}
			time++;
			return false;						//Nope
		}
};

and z player

class ZPlayer : public Adafruit_VS1053_FilePlayer {
  public:
	boolean started;
	
	ZPlayer(
	       int8_t rst, int8_t cs, int8_t dcs, int8_t dreq, int8_t cardcs) 
	: Adafruit_VS1053_FilePlayer(rst, cs, dcs, dreq, cardcs)  {	}
	
	void play() {	//Call every iteration
		feedBuffer();
	}
	boolean startFile(char* name) {
		currentTrack = SD.open(name);
		if (!currentTrack) {
			return false;
		}

		playingMusic = false;
		started = true;

		// wait till its ready for data
		while (! readyForData() );
		
		Serial.println("Playing File. . .");
		
		return true;
	}
};

so, we've made quite a bit of progress, but we're still having some major issues. I am hoping someone can actually help with these ones, since we're not asking for a code that isn't a cut and paste answer.

To start with, I moved the analog pin to A4 for the mic (since the only indication I can find on pins that actually aren't used say A4 and A5 are free). The reason for that, I'll get to later. Next up, we called the pull up resistor for that pin (again, more on that later). I've tried aRef to no avail (bridging to the 3.3v pad I'm connected to) so either that's not how aRef works, or setting analogreference to external isn't what I need to be doing.

We have already been able to get the microphone to modulate the output of the speakers when I talk (you'll understand why I worded it that way momentarily). The problem is that it isn't modulating nothing, it's modulating a ridiculously loud tone that happens when even the mic is unplugged. Here's where it gets weird. We moved to a4, saw no change, and then I completely removed the analog wire from the board. Finally it was quiet (or quiet enough to filter out in code). So, just by connecting a wire to the board, with nothing on the other end, we get a tone that's louder than the output from our mic, drowning out both sounds and silence (because it is never silent).

Just for the heck of it, I called the pull up resistor on pin A4. The tone when a wire was connected (with nothing on the other end) was virtually gone. However, when I plug the microphone in (even if it's just the analog wire and not the VCC or GND) the tone starts again. I can still make the thing modulate by talking into it, but it sounds really crappy and the tone at zero mic input still is louder than what comes out when I talk (and the loud noise doesn't stop when I talk).

What could be causing this interference, and how do I stop it?

you shouldn't need any of the other libraries to check over this. If you do, you should already have the needed ones since we aren't calling any player functions, and the one we are using comes from the wave shield libraries.

the only difference in the code that produced all of the things I mention and this one is the analog reference being changed. I'm going to try a different configuration for the aref when I get home, so I uploaded the code I need for that ahead of time.

Any help here would be great, and the sooner the better. We've already done the hard part (with almost no help from anywhere I've asked) and I'd sure appreciate some suggestions.

agordon117

Posts: 4
Joined: Sat Nov 01, 2014 7:50 pm

/*************************************************** 
* This is an example for the Adafruit VS1053 Codec Breakout
* Designed specifically to work with the Adafruit VS1053 Codec Breakout 
* ----> https://www.adafruit.com/products/1381
* 
* Adafruit invests time and resources providing this open source code, 
* please support Adafruit and open-source hardware by purchasing 
* products from Adafruit!
* 
* Written by Limor Fried/Ladyada for Adafruit Industries.  
* BSD license, all text above must be included in any redistribution
****************************************************/

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include "WaveStructs.h"
#include "Button.h"
#include "ZPlayer.h"


// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

ZPlayer musicPlayer = 
// create breakout-example object!
//Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
// create shield-example object!
ZPlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
int lVolume=20;
int rVolume=20;
int Volume=20;
int inPin[4] = {
 A1, 5, A2, A5};

int counterA = 0;       // how many times we have seen new value  
int counterB = 0;
int counterC = 0;
int counterD = 0;

int lastStateD = 0;

int MAXVOLUME = 100;
int MaxTrack = 2;

long timeA = 0;
long timeB = 0;
long timeC = 0;
long timeD = 0;
int debounce_count =2;
uint8_t hBuffer[44];
boolean headerLoaded;

/*
char tracks[2][13] = {   //The first number is the number of tracks. 12 Character names + null terminator.
  "track001.mp3",
  "track002.mp3",
}
*/

Button buttonA(A1);
Button buttonB(5);
Button buttonC(A2);
Button buttonD(A5);

uint16_t aBuffer;
uint8_t dBuffer[2];

//   Functions


void setup() {
 Serial.begin(9600);
 Serial.println("Adafruit VS1053 Library Test");

 pinMode(A4, INPUT_PULLUP);
  analogReference(EXTERNAL);
 // initialise the music player
 if (! musicPlayer.begin()) { // initialise the music player
   Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
   while (1);
 }
 Serial.println(F("VS1053 found"));

 //musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

 if (!SD.begin(CARDCS)) {
   Serial.println(F("SD failed, or not present"));
   while (1);  // don't do anything more
 }
 Serial.println("SD OK!");

 // list files
 printDirectory(SD.open("/"), 0);

 // Set volume for left, right channels. lower numbers == louder volume!
 musicPlayer.setVolume(lVolume,rVolume);

 /***** Two interrupt options! *******/
 // This option uses timer0, this means timer1 & t2 are not required
 // (so you can use 'em for Servos, etc) BUT millis() can lose time
 // since we're hitchhiking on top of the millis() tracker
 //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);

 // This option uses a pin interrupt. No timers required! But DREQ
 // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
 // that's Digital #2 or #3
 // See http://arduino.cc/en/Reference/attachInterrupt for other pins
 // *** This method is preferred
 if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
   //Serial.println(F("DREQ pin is not an interrupt pin"));
  
 headerLoaded = false;
}

void loop() {
/*   if(!musicPlayer.started) {
     if(!musicPlayer.startFile("track001.wav")) {
        break;
     }
  }

  handleInput();

  if(musicPlayer.playingMusic) {
     musicPlayer.play();
  }
*/
   playMic();
}

void playMic() {
  if(!headerLoaded) {
     loadWAVHeader();
     headerLoaded = true;
  }
  while(!musicPlayer.readyForData());

  aBuffer = map(analogRead(4), 0, 1023, 0, 0xFFFF);
//   aBuffer = (analogRead(4) * 1);

  dBuffer[0] = aBuffer & 0xFF; 
  dBuffer[1] = (aBuffer >> 8) & 0xFF;

   musicPlayer.playData(dBuffer, 2);
}
  

void loadWAVHeader() {
  int size = 8000000;
  int sampleRate = 9600;
  int channels = 1;
  int bps = 16;
  
  // fill in wave file header
  WaveHeader *header = reinterpret_cast<WaveHeader *>(hBuffer);
  // RIFF chunck
  strncpy_P(header->riff.id, PSTR("RIFF"), 4);
  header->riff.size = 0xFFFFFFFF;
  strncpy_P(header->riff.type, PSTR("WAVE"), 4);
  // fmt chunck
  strncpy_P(header->fmt.id, PSTR("fmt "), 4);
  header->fmt.size = sizeof(WaveFmt) - 8;
  header->fmt.formatTag = WAVE_FORMAT_PCM;
  header->fmt.channels = channels;
  header->fmt.sampleRate = sampleRate;
  header->fmt.bytesPerSecond = sampleRate * channels * bps / 8;
  header->fmt.blockAlign = channels * bps / 8;
  header->fmt.bitsPerSample = bps;
  // data chunck
  strncpy_P(header->data.id, PSTR("data"), 4);
  header->data.size = 0xFFFFFFFF;

  musicPlayer.playData(hBuffer, 44);
}

void handleInput() {
 //Play / Pause
 if(buttonD.pressed()) {
   if(!musicPlayer.playingMusic) {
     musicPlayer.playingMusic = true;      //Unpause
   }
   else {
     musicPlayer.playingMusic = false;      //Pause
     Serial.println("Paused.");
   }
 }

 //Volume
 if (buttonA.pressed()) {   //A
   VolumeDown();
   Serial.println("Changing Volume");
   Serial.print("Volume is now set to: ");
   Serial.println(lVolume);
   musicPlayer.setVolume(lVolume,rVolume);
 }

 timeB = millis();

 if (buttonB.pressed()) {   //B
   VolumeUp();
   Serial.println("Changing Volume");
   Serial.print("Volume is now set to: ");
   Serial.println(lVolume);
   musicPlayer.setVolume(lVolume,rVolume);
 }

 //Skip

}

void VolumeDown(){
 int MAX = MAXVOLUME;
 int MIN = 1;

 if( Volume < MAX){ //Lower Volume
   //Volume++;
   Volume = Volume +5; //use this to increase by a number other than 1
   lVolume = Volume;
   rVolume = Volume;
 }
} 

void VolumeUp(){
 int MAX = MAXVOLUME;
 int MIN = 1;

 if(Volume > MIN) {//&& Volume <= MAX){ //Raise health
   //Volume--;
   Volume = Volume -5; //use this to increase by a number other than 1
   lVolume = Volume;
   rVolume = Volume;
 }
}

/*
void NextTrack(){  
  timeB = millis();  
  readingB = digitalRead(inPinB);
  
  if(readingB != current_stateB) {
     current_stateB = readingB;
     if (current_stateB == HIGH) {
        VolumeUp();
        Serial.println("Changing Volume");
        Serial.print("Volume is now set to: ");
        Serial.println(lVolume);
        musicPlayer.stopPlaying();
     }
  
  }
  timeB = millis()
}
*/

/// File listing helper
void printDirectory(File dir, int numTabs) {
 while(true) {

   File entry =  dir.openNextFile();
   if (! entry) {
     // no more files
     //Serial.println("**nomorefiles**");
     break;
   }
   for (uint8_t i=0; i<numTabs; i++) {
     Serial.print('\t');
   }
   Serial.print(entry.name());
   if (entry.isDirectory()) {
     Serial.println("/");
     printDirectory(entry, numTabs+1);
   } 
   else {
     // files have sizes, directories do not
     Serial.print("\t\t");
     Serial.println(entry.size(), DEC);
   }
   entry.close();
 }
}

If you want help you should post the code that is running. That code you posted will not compile.

We get readings around 300 when silent, and around 700 when the mic reads loud noises.

That does not sound correct, when there is a sound there should be numbers both above and below the silent value.
As you are only seeing numbers above it it looks like you have a sound level detector and not a microphone input.

I'm really hoping someone here can tell me what we need to do with the output values from the mic to make them readable by the mp3/wav/ogg/etc codec player.

That is not possible.

Are you using this microphone board - Electret Microphone Amplifier - MAX4466 with Adjustable Gain : ID 1063 : $6.95 : Adafruit Industries, Unique & fun DIY electronics and kits - and this shield - Adafruit Music Maker MP3 Shield for Arduino w/3W Stereo Amp [v1.0] : ID 1788 : $34.95 : Adafruit Industries, Unique & fun DIY electronics and kits?

Which device does the microphone board deliver its output to - the Uno, or the shield?