| 
  • If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!

View
 

Akshay Trikha Final Project

Page history last edited by akshayt@... 8 years, 8 months ago

Final Project Document

 

Initial Idea

I live in very close proximity to a city space, and also park. My original idea involved me creating an iPod shuffle sized mp3 player that could read the ambient sound levels and adjust volume of a song playing accordingly, because I found myself having to change the volume myself quite frequently. I was very wrong about the size of my final project, and a bit off from the final microphone functionality.

 

Verplank Diagram

 

 

After actually sourcing my parts from Adafruit and realising how big they were, it struck me that I would never be able to achieve

the size of an mp3 player that I had wanted.

 

 

I then pivoted on my idea onto making an mp3 player that mutes every time that you or someone else talk's so you can actually hear your conversation

without unplugging your earphones (as I found this to be quite the hassle)

 

I didn't actually make a paper model design, instead I focused more on making the product work instead, and then designing a workaround case for it.

 

Project Code

 

Credit to Frank Zhao, Matthew Seal, David Sirkin, Akil Srinivasan, Learn.Adafruit for most of the code.

 

The only lines that I have written in this code are lines: 44,46, 47, 204, 218, 234, 245, 259, 260, and a lot of rearranging

 

/*

 * example sketch to play audio file(s) in a directory, using the mp3 library

 * for playback and the arduino sd library to read files from a microsd card.

 * pins are setup to work well for teensy 2.0. double-check if using arduino.

 *

 * originally based on frank zhao's player: http://frank.circleofcurrent.com/

 * utilities adapted from previous versions of the functions by matthew seal.

 *rsirkin@cdr.stanford.edu

 *                & akil srinivasan akils@stanford.edu

 */

 

// ---- includes and defines ------------------------------------------------

 

// first step is to include (arduino) sd, eeprom and (our own) mp3 libraries.

 

 

 

#include <SD.h>

#include <SPI.h>

#include <EEPROM.h>

 

#include <mp3.h>

#include <mp3conf.h>

 

// setup microsd and decoder chip select pins, and the decoder-specific pins.

 

#define sd_cs         17        // 'chip select' line for the microsd card

 

#define mp3_cs        A0        // 'command chip select' connect to cs pin

#define mp3_dcs       A1        // 'data chip select' connect to bsync pin

#define mp3_rst       -1        // 'reset' connects to decoder's reset pin

#define mp3_dreq      A2        // 'data request line' connect to dreq pin

 

// now assign pins for the graphic lcd (carried over from the etch-a-sketch).

 

#define lcd_dc        A4        // 'data/command input' connect to d/c pin

#define lcd_cs        A3        // 'slave chip select' connects to  cs pin

#define lcd_rst       -1        // 'reset' connects to graphic lcd rst pin

 

// 'read_buffer' is the amount of data read from microsd and sent to decoder.

// it's probably best to keep this a factor of 2, up to about 1kb (2kb is the

// max). you might change this if you experienced skips during song playback.

 

#define read_buffer  1024   // size (bytes) of the microsd read buffer

 

byte mp3_vol = 200;

volatile long pauseCounter;

 

// file names are 13 bytes max (8 + '.' + 3 + '\0'), and the file list should

// fit into the eeprom. for example, 13 * 40 = 520 bytes of eeprom are needed

// to store a list of 40 songs. if you use shorter file names, or if your mcu

// has more eeprom, you can change these.

 

#define max_name_len  13

#define max_num_songs 40

 

// id3v2 tags have variable-length song titles. that length is indicated in 4

// bytes within the tag. id3v1 tags also have variable-length song titles, up

// to 30 bytes maximum, but the length is not indicated within the tag. using

// 60 bytes here is a compromise between holding most titles and saving sram.

 

// if you increase this above 255, look for and change 'for' loop index types

// so as to not to overflow the unsigned char data type.

 

#define max_title_len 60

 

// ---- global variables ----------------------------------------------------

 

// 'File' is a wrapper of the 'SdFile' data type from the sd utility library.

 

File sd_file;                   // object to represent a file on a microsd

 

// store the number of songs in this directory, and the current song to play.

 

unsigned char num_songs = 0, current_song = 0;

 

// an array to hold the current_song's file name in ram. every file's name is

// stored longer-term in the eeprom. this array is used in 'sd_file.open()'.

 

char fn[max_name_len];

 

// an array to hold the current_song's title in ram. it needs 1 extra char to

// hold the '\0' that indicates the end of a character string. the song title

// is found in 'get_title_from_id3tag()'.

 

char title[max_title_len + 1];

 

// the program runs as a state machine. the 'state' enum includes the states.

// 'current_state' is the default as the program starts. add new states here.

 

enum state { DIR_PLAY, MP3_PLAY, PAUSED };

state current_state = DIR_PLAY;

 

//---- module functions -----------------------------------------------------

 

// you must open a song file that you want to play using 'sd_file_open' prior

// to fetching song data from the file. you can only open one file at a time.

 

void sd_file_open() {

  // first, find the file name (that's stored in eeprom) of the current song.

 

  get_current_song_as_fn();

 

  // then open the file using the name we just found (stored in 'fn' global).

 

  sd_file = SD.open(fn, FILE_READ);

 

  // find the current song's title tag (if present) then print it to the lcd.

 

  print_title_to_lcd();

}

 

// read a number of bytes from the microsd card, then forward them to the Mp3

// library's 'play' function, which streams them out to the decoder chip.

 

void mp3_play() {

  unsigned char bytes[read_buffer]; // buffer to read and send to the decoder

  unsigned int bytes_to_read;       // number of bytes read from microsd card

 

  // first fill the 'bytes' buffer with (up to) 'read_buffer' count of bytes.

  // that happens through the 'sd_file.read()' call, which returns the actual

  // number of bytes that were read (which can be fewer than 'read_buffer' if

  // at the end of the file). then send the retrieved bytes out to be played.

 

  // 'sd_file.read()' manages the index pointer into the file and knows where

  // to start reading the next batch of bytes. 'Mp3.play()' manages the index

  // pointer into the 'bytes' buffer and knows how to send it to the decoder.

 

  bytes_to_read = sd_file.read(bytes, read_buffer);

  Mp3.play(bytes, bytes_to_read);

 

  // 'bytes_to_read' is only smaller than 'read_buffer' when the song's over.

 

  if (bytes_to_read < read_buffer) {

    sd_file.close();

 

    // if we've been in the MP3_PLAY state, then we want to pause the player.

 

    if (current_state == MP3_PLAY) {

      current_state == PAUSED;

    }

  }

}

 

// continue to play the current (playing) song, until there are no more songs

// in the directory to play. 2 other sd library methods (that we haven't used

// here) can help track your progress while playing songs: 'sd_file.size()' &

// 'sd_file.position()'. you can use these to show say, the percent of a song

// that has already played.

 

void dir_play() {

  if (sd_file) {

    mp3_play();

  }

  else {

    // since 'sd_file' isn't open, the recently playing song must have ended.

    // increment the index, and open the next song, unless it's the last song

    // in the directory. in that case, just set the state to PAUSED.

 

    if (current_song < (num_songs - 1)) {

      current_song++;

      sd_file_open();

 

    }

    else {

      current_state = PAUSED;

    }

  }

}

 

// ---- setup and loop ------------------------------------------------------

 

// setup is pretty straightforward. initialize serial communication (used for

// the following error messages), mp3 library, microsd card objects, then the

// graphic lcd. then open the first song in the root library to play.

 

void setup() {

  // if using a graphic lcd, initialize with contrast, then setup the screen.

 

  // initialize the mp3 library, and set default volume. 'mp3_cs' is the chip

  // select, 'dcs' is data chip select, 'rst' is reset and 'dreq' is the data

  // request. the decoder sets the 'dreq' line (automatically) to signal that

  // its input buffer can accommodate 32 more bytes of incoming song data.

 

  // the decoder's default state prevents the spi bus from working with other

  // spi devices, so we initialize it first.

 

  Mp3.begin(mp3_cs, mp3_dcs, mp3_rst, mp3_dreq);

  Mp3.volume(mp3_vol);

 

  // initialize the microsd (which checks the card, volume and root objects).

 

  sd_card_setup();

 

  // putting all of the root directory's songs into eeprom saves flash space.

 

  sd_dir_setup();

 

  // the program is setup to enter DIR_PLAY mode immediately, so this call to

  // open the root directory before reaching the state machine is needed.

 

  sd_file_open();

 

  attachInterrupt(1, pause, CHANGE);

}

 

// the state machine is setup (at least, at first) to open the microsd card's

// root directory, play all of the songs within it, close the root directory,

// and then stop playing. change these, or add new actions here.

 

// the DIR_PLAY state plays all of the songs in a directory and then switches

// into PAUSED when done. the MP3_PLAY state plays one specific song and then

// switches into PAUSED. this sample player doesn't enter the MP3_PLAY state,

// as its goal (for now) is just to play all the songs. you can change that.

 

void loop() {

 

  while (pauseCounter % 2 == 0) {

    switch (current_state) {

 

      case DIR_PLAY:

        dir_play();

        break;

 

      case MP3_PLAY:

        mp3_play();

        break;

 

      case PAUSED:

        break;

    }

 

 

    const int sampleWindow = 20; // Sample window width in mS (50 mS = 20Hz)

    unsigned int sample;

    unsigned long startMillis = millis(); // Start of sample window

    unsigned int peakToPeak = 0;   // peak-to-peak level

 

    unsigned int signalMax = 0;

    unsigned int signalMin = 1023;

 

    // collect data for 50 mS

    while (millis() - startMillis < sampleWindow)

    {

      sample = analogRead(A5);

      if (sample < 1024)  // toss out spurious readings

      {

        if (sample > signalMax)

        {

          signalMax = sample;  // save just the max levels

        }

        else if (sample < signalMin)

        {

          signalMin = sample;  // save just the min levels

        }

      }

 

      peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude

      mp3_vol = byte(map(peakToPeak, 1023, 0, 0, 254));

      Mp3.volume(mp3_vol);

    }

  }

}

 

void pause()

{

  static unsigned long last_interrupt_time = 0;

  unsigned long interrupt_time = millis();

  // If interrupts come faster than 200ms, assume it's a bounce and ignore

  if (interrupt_time - last_interrupt_time > 200)

  {

    pauseCounter++;

  }

  last_interrupt_time = interrupt_time;

}

 

Producing It

 

I had a lot of issues with the 4050 chip. By the end of it all I hated it with a passion because one way or a another,

it would find a way to cause mayhem for e.g. my first two ones were dysfunctional, double the connections meant 

double the wires etc. etc. 

 

Fliqz has shut down their service. To access this video, email support with this video id: 490ace102b594f39a3d4c7253204a6ec

 

So I thought why not just run 3.3V into the Vin pin of the Arduino to make all of the logic run in 3.3V. This would 

mean running the Arduino at a lower clock speed and potentially taking a minor risk in damaging it, but it worked 

out for me.

 

 

I first placed all my components onto a breadboard neatly, in order to test if my circuit actually worked.

I would highly recommend keeping things clean on a breadboard because it makes debugging and life a lot easier.

 

 

After I knew everything worked and was satisfied with my circuit, I moved onto soldering everything together.

 

 

 

After soldering everything together, I had to debug the circuit a few times and eventually, everything was powered!

 

 

 

After I knew everything worked, I then began making the case for my mp3 player. I made all the appropriate

measurements for holes, and then began producing it. 

 

 

 

The finished product :)

 

 

Fliqz has shut down their service. To access this video, email support with this video id: 6f0a38dc423945dca839445fa559f2c0

Fliqz has shut down their service. To access this video, email support with this video id: c7fdb8419ce147928a06c04fc989f557

 

Comments (2)

xyyue@... said

at 2:47 pm on Aug 18, 2015

Hi Trikha,

We do love your ideas, the initial one and the later one of muting. These ideas are really practical and helpful for us. We hope that you could finish implementing the idea even after the course is over. Your Verplank Diagram is really good and the comments in the code is pretty detailed.

We hope that you could provide more details on the implementation of the device. We also hope that you can really finish the project and make it a working device.

Well done during the summer and good luck!

David S said

at 11:03 am on Nov 5, 2015

Hello Akshay,

Here’s an update to our earlier feedback, now that you've completed the report…

First, you have a great original idea. I don’t recall prior students implementing this idea before, so you are (well, were) onto a new approach (for us, at least).

Your 3.3V hack is a great workaround. Based on our troubles with the 4050 this summer, we’ll be moving to the Arduino Metro next time, which is an ATMega 328, with dedicated FTDI (USB) chip, and (most importantly) convertible to 3.3V by slicing a trace on the bottom of the board.

We can’t really tell from the report if your auto-mute functionality is working, but we can read in your code where you implemented the feature. Did you add a feature (during or after class ended) to re-adjust the volume back to its original level after the ambient volume changes it?

In the report, we like your Verplank diagram, and notice that your metaphor is really just a description of what you plan to make. Metaphors can be challenging, but also rewarding. How about the human voice? When we’re in a crowded environment, we speak up, right? How about a car radio that increases the volume as the car’s speed increases, due to additional road noise? There’s a lot of these!

For other parts of the report, you describe your motivation and point-of-view well, and, we would like to have seen some design sketches and a state diagram.

We hope that you had a good summer, learned about interactive devices, continue working in areas like mechatronics and continually improve your project. Have a great year!

Best Regards, David, Samyuktha, Dongao, Praveen, Tian, Xiangyu and Zahra

You don't have permission to comment on this page.