| 
  • 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
 

Shim, Arthur Final Project (1)

Page history last edited by Arthur Shim 8 years, 8 months ago

Music Mixing Mp3

 

My original design was to create an Mp3 player with a function to change the speed of songs being played. The long term goal was to create a device that was basically two mp3 players combined into one. It would be able to play two different songs at once, and by shifting the speed and volume of the songs and with the correct timing and pitch, the two songs could be mixed together to make an entirely new sound. It's similar to a DJ device, only simpler and a little harder to use.

 

The device would also have the usual functions of an mp3 player, like a pause/play button, a button to go to the next song, a button to go to the previous song, and a headphone jack. There would be two speakers to play the two songs and two LCD screens to display the songs being played. Both songs would accessed from one SD card, meaning there would also be an SD card slot.

 

This was the first design which was just one mp3 player with a speed knob:

 

 

This is the second design, which is two mp3 players combined into one:

 

 

The second design also has a pause/play button that controls both mp3s. So both will be paused or played when the button is pressed. It also has another speed knob and volume knob that controls both mp3s.

I chose to design this kind of device because I like to mix music in my free time. I do all my music work on my computer, but having a physical device that I can use to mix music live would be neat to have. I also have a friend who composes and mixes music, and I thought a device like this would be helpful for him, or at least fun to play with.

 

Verplank Diagram:

State Diagram:

 

 

Paper prototype:

 

 

In order to create this kind of mp3 player you need the following items:

  • breadboard (for prototyping)

  • wires

  • 3 buttons

  • 1 potentiometer

  • Arduino micro

  • 3.5 mm audio jack

  • micro SD card

  • micro SD card adapter

  • VS1053 decoder chip

  • Graphical LCD

  • HEF4050B

  • perf board (for final device)

  • soldering iron, solder, etc.

  • Arduino software

I connected the parts based off of the instructions for the barebones mp3 in lab 6. I connected the SD card adapter using the instructions from lab 5. I used the potentiometer as the volume control knob.

Unfortunately due to time constraints some of the features had to get cut from the final design. I didn't have time to implement a speed knob or create two mp3 players. I was able to get an LCD screen, pause/play button, volume knob, and a button to move to the next song.

The original plan was to create the circuit on a breadboard, perf board it, and then put it in a box so that it looked cleaner and easier to use for a user.

I started by creating the circuit on a breadboard. After testing it and making sure it worked, I moved on to rebuilding the circuit on a perf board. In order to get the entire circuit to fit, I used two perf boards that would fold over each other. I used female headers so I didn't have to solder my components directly into the board which would have made them impossible to move around.

 

 

 

In order to give myself an easier time debugging, I color coded my wires. I made all of my wires running to power red and all of the wires running to ground purple. Any other wire would be yellow.

One of the challenges I face while perf boarding was I made an error while soldering down female headers for the Arduino micro. I didn't make the headers far enough from each other. I had to unsolder some wires and solder in a new set of female headers. It was challenging to get the wires out, but I took my time and was able to successfully get them out.

I gave myself four days to perf board my circuit. This turned out to be enough time since I was able to finish perf boarding in three days. I then used another day to cut out a box for my mp3 player. I used wood for the box to keep things simple.

 

 

There were many challenges I faced while creating this mp3 player. After perf boarding the circuit, I moved the components from the breadboard to the perf board and tested it out. On the third try of running the programming, the circuit worked. I hadn't added the buttons to the perf board yet, but the music was playing properly and the LCD was displaying the song name like it was supposed to. In my excitement, I didn't think to film the functioning mp3 on perf board.

The next time I tried the circuit, it didn't work. All of the components lit up properly and the LCD was functioning, but no music was playing and the LCD was blank. This was the biggest challenge I faced, and that I still face. I spent two days debugging the perf board and trying to figure out what went wrong. I first used a multimeter to check the connections to make sure everything was really connected. I found some of the pins on the 4050 weren't connecting. I brought this problem up with the TA's and saw that some other students were facing the same problem. Initially I was going to solder the 4050 directly into the perf board, knowing that it was risky since if I made a mistake, there would be no way to move the 4050 easily out of the perf board without damaging it. However the TA's and instructors provided me with another solution. They found female headers specifically designed for another component, but could be used to fit the 4050 into. I tried this, and used this new female header with my old one to fit the 4050 into my board. I rechecked the connections and everything was connected. Unfortunately, it didn't solve the problem. All the parts lit up, but no music played and nothing was displayed.

 

I then tried sineTest, readWrite, Strings, and blink to see if any of my components were malfunctioning. Only blink successfully worked. I tried switching out my mp3 decoder with another student's who knew it was functioning to see if my decoder was the problem. It wasn't, and the same problem persisted with the new decoder.

 

I moved all the components back to the breadboard and tried my breadboard circuit again. After restarting the arduino micro a few times, the Mp3 program began running. Everything worked fine on the breadboard, including the buttons.

I figured this meant that there was a problem with my wiring on my perf board. I put all the components back on the perf board and then I checked to make sure I had wires running to all the right places. I checked the perf board off of the breadboard and the instructions from lab 5 and 6. Unfortunately, all of my connections were correct, meaning that wasn't the problem.

 

I then took a multimeter and checked to make sure the wiring was actually connecting the components to the right parts and pins. I also checked to make sure that there weren't any bridges in my soldering that weren't supposed to be there and that there were no connections that I wasn't supposed to have. I didn't have.

 

 

Due to time constraints, I wasn't able to continue figuring out why my perf board circuit wasn't working. I did get it to work once, but since that one time all of the components have lit up properly, but no music has been played and no text displayed. I still don't know why this is happening.

My mp3 player is functioning on the breadboard. Though I wasn't able to implement the speed function, most of the other functions made it onto the device.

 

Pictures:

 

 

Video:

 


 

This is the code for my mp3 player.

Code:

// 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>

 

// include the adafruit pcd8544 & gfx libraries for a nokia 5110 graphic lcd.

 

#include <Adafruit_GFX.h>

#include <Adafruit_PCD8544.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 512 // size (bytes) of the microsd read buffer

#define mp3_vol 190 // default volume. range min=0 and max=254

 

// 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 ----------------------------------------------------

 

// instantiate a graphic lcd object using the pins that we #define'd earlier.

// comment out the graphics lines to save memory if you're not using the lcd.

 

// Adafruit_PCD8544 lcd = Adafruit_PCD8544(lcd_clk, lcd_din, lcd_dc, lcd_cs, lcd_rst);

Adafruit_PCD8544 lcd = Adafruit_PCD8544(lcd_dc, lcd_cs, lcd_rst);

 

// '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 };

volatile 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_song = 0;

sd_file_open();

}

}

}

 

int lastSeen = 0;

void dir_playPause()

{

if (millis() - lastSeen < 500) {

lastSeen = millis();

return;

}

lastSeen = millis();

if (current_state == DIR_PLAY)

current_state = PAUSED;

else if (current_state == PAUSED)

current_state = DIR_PLAY;

}

 

int lastSeen1 = 0;

void nextSong()

{

if (millis() - lastSeen1 < 500) {

lastSeen1 = millis();

return;

}

lastSeen1 = millis();

 

sd_file.close();

if (current_song < (num_songs - 1))

{

current_song++;

}

else

current_song = 0;

sd_file_open();

}

 

int lastSeen2 = 0;

void prevSong()

{

if (millis() - lastSeen2 < 500) {

lastSeen2 = millis();

return;

}

lastSeen2 = millis();

 

sd_file.close();

if (current_song > 0)

{

current_song--;

}

else

current_song = (num_songs - 1);

sd_file_open();

}

 

// ---- 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.

 

pinMode(2, INPUT);

attachInterrupt(1, dir_playPause, RISING);

pinMode(1, INPUT);

attachInterrupt(3, nextSong, RISING);

// pinMode(0, INPUT);

// attachInterrupt(2, prevSong, RISING);

 

lcd.begin(55);

lcd.display();

delay(500);

 

lcd.clearDisplay();

lcd.print("Barebones Mp3!");

lcd.display();

delay(500);

 

// 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();

}

 

// 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() {

switch(current_state) {

 

case DIR_PLAY:

dir_play();

break;

 

case MP3_PLAY:

mp3_play();

break;

 

case PAUSED:

break;

}

}

Comments (1)

xyyue@... said

at 1:53 pm on Aug 18, 2015

Hi Arthur,

Your idea of the mixing sound device is pretty excellent and creative. Your Verplank and State diagrams are also clear.

Although you haven't finished your idea in the limited time period, we do see your effort on the final project. Sometimes the debugging process is really annoying so you have to be careful from the beginning.

We love your idea and hope that you could continue and finish this wonderful device!

Well done during the summer and good luck!

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