Arduino Forum

Using Arduino => Audio => Topic started by: mynab on Feb 09, 2011, 09:43 am

Title: Ethernet MP3 Player
Post by: mynab on Feb 09, 2011, 09:43 am
Hello,

I would like to build a small box being able to play MP3 from the network (Ethernet cable for the moment, Wifi maybe later) and output the sound to my amplifier. Being brand new to Arduino and electronics, I want to check my understanding of it before ordering the parts so thanks for your feedback.

From what I understood, I of course need an Ethernet shield and an MP3 shield. Using Ethernet.Client I would read the bytes of the MP3 stream and feed them to the MP3 shield most probably using a serial interface and Serial.write.

I have two possible choices in mind:

1) Aduino Uno + Ethernet shield + Sparkfun VS1053D MP3
2) Rogue Robotics rMP3 + Ethernet shield. Not sure at all about this but I kind of understood that the rMP3 had its own microcontroller...

So please can you please give me your feedback about this:
- Am I right with my bytes read from Ethernet and fed to the MP3 shield using serial?
- Of the two choices, which one is good one?

If it is feasible I would prefer to use the 1st design so I can also do other stuff with Arduino Uno in the learning stage...

Thanks!
mynab
Title: Re: Ethernet MP3 Player
Post by: mowcius on Feb 09, 2011, 10:50 am
There is someone else working on this with the rMP3 module.
Although it has its own processor, that is for controlling the module and you are much better off using an arduino as well to control the ethernet shield and the rMP3

As someone is already working on it, I'd be tempted towards the rMP3 if I were you. It also has a load of features that the MP3 board from sparkfun does not have.
Title: Re: Ethernet MP3 Player
Post by: mynab on Feb 09, 2011, 12:10 pm
Thanks! Do you know who is working on that?

What about PIN conflicts? I see that rMP3 both use D11 to D13. Are these shareable?
Title: Re: Ethernet MP3 Player
Post by: mowcius on Feb 09, 2011, 12:40 pm

Thanks! Do you know who is working on that?

What about PIN conflicts? I see that rMP3 both use D11 to D13. Are these shareable?

Have a read from the last post on this thread (http://arduino.cc/forum/index.php/topic,7017.105.html) onwards.

The rMP3 only requires pins +5, GND, Digital 6 and Digital 7. The other pins are unused in normal operation.

You can however connect pins 6 and 7 to whatever pins you like on the board as they are simply used for serial communication (NewSoftSerial) and you can define them as any pins on the arduino.
Title: Re: Ethernet MP3 Player
Post by: mynab on Feb 09, 2011, 02:22 pm
Thanks. I contacted LB01 but from what I understand, music MP3 (128kps+) will not be possible with that kind of design because of the serial communication between Ethernet and MP3 right? So I need Rogue Robotics to put an Ethernet plug on their card  :)
Title: Re: Ethernet MP3 Player
Post by: mowcius on Feb 09, 2011, 02:34 pm
Yeah, I thought that might be the bottleneck in the system.

I'll nudge bhagman this way later and see if he has any ideas.
Title: Re: Ethernet MP3 Player
Post by: mynab on Feb 18, 2011, 02:21 pm
Hi. Did you have a chance to talk to bhagman? I sent him a message but got no answer   :(
Title: Re: Ethernet MP3 Player
Post by: mowcius on Feb 18, 2011, 02:26 pm
Oh sorry I forgot...

I'll send him an email. :)
I know he's a busy man though ;)
Title: Re: Ethernet MP3 Player
Post by: bhagman on Feb 24, 2011, 11:42 pm
Sorry guys - got a few things on my plate.

I've been wanting to write this streaming MP3 player, but I just don't have the time.

I'm pretty sure it can be done - with some limitations.  The MP3 bitrate will have to be pretty low (96 kbps or lower), but in most cases, that can still sound pretty good - especially mono (which you can do at 64 kbps and get pretty decent quality).

You will need to communicate with the rMP3 using a hardware serial port @ 115200 or better.  Some boards, like our LEDHead (http://www.roguerobotics.com/products/electronics/ledhead) for example, have 2 or more hardware serial ports.  You can use the first serial port, but you won't have any feedback to the serial monitor, if that's your intention (and you may have to disconnect the USB cable, if your board has an on-board USB controller).

Furthermore, it will require buffering data to files, and switching on the fly as data is received.  I can get into more detail about this, if someone wants to take on the task of building the streaming MP3 player.


b
Title: Re: Ethernet MP3 Player
Post by: LBArduino on Apr 17, 2011, 01:03 pm
Hi all,

I hope mynab is still working on that project? I did something similar last December. I have been stopped for a while but I managed to restart recently.

I use an ethershield with the ship enc28j60 (the cheap one), and that needs a special library. You may not be able to re-use my code if you don't use that kind of ethernet shield.

So far, I have been able to capture a stream on my serial port. My arduino connects to a given site, requests the stream, find the beggining of the data and sends the rest to the serial port so that if you capture it, you get an mp3 file that can be played normally.

Here is the code, modified from the ethershield Pachube example (to connect to a french radio):

Code: [Select]

/*
* Read a pachube data streem and report results as csv
*/
# define WWW_client

#include <EtherShield.h>

static uint8_t mymac[6] = {0x54,0x55,0x99,0x10,0x00,0x25};
static uint8_t myip[4] = {192,168,1,1};
// Default gateway. The ip address of your DSL router. It can be set to the same as
// websrvip the case where there is no default GW to access the
// web server (=web server is on the same lan as this host)
static uint8_t gwip[4] = {192,168,1,254};

//============================================================================================================
// Pachube declarations
//============================================================================================================
#define PORT 80                   // HTTP

// the etherShield library does not really support sending additional info in a get request
// here we fudge it in the host field to add the API key
// Http header is
// Host: GET http://mp3.live.tv-radio.com/franceinter/all/franceinterhautdebit.mp3
// User-Agent: Arduino/1.0
// Accept: text/html
#define HOSTNAME "mp3.live.tv-radio.com\r\nKeep-Alive: 300"      // API key
static uint8_t websrvip[4] = { 0,0,0,0 }; // Get pachube ip by DNS call
#define WEBSERVER_VHOST "mp3.live.tv-radio.com"
#define HTTPPATH "/franceinter/all/franceinterhautdebit.mp3"      // Set your own feed ID here

//#define HOSTNAME "www.pachube.com\r\nX-PachubeApiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"      // API key
//static uint8_t websrvip[4] = { 0,0,0,0 }; // Get pachube ip by DNS call
//#define WEBSERVER_VHOST "www.pachube.com"
//#define HTTPPATH "/api/0000.csv"      // Set your own feed ID here

static uint8_t resend=0;
static int8_t dns_state=0;

EtherShield es=EtherShield();

#define BUFFER_SIZE 900
static uint8_t buf[BUFFER_SIZE+1];

void browserresult_callback(uint8_t statuscode,uint16_t datapos){
//  if (datapos != 0)
//  {
//    // now search for the csv data - it follows the first blank line
//    // I'm sure that there is an easier way to search for a blank line - but I threw this together quickly
//    // and it works for me.
//    uint16_t pos = datapos;
//    while (buf[pos])    // loop until end of buffer (or we break out having found what we wanted)
//    {
//      while (buf[pos]) if (buf[pos++] == '\n') break;   // find the first line feed
//      if (buf[pos] == 0) break; // run out of buffer
//      if (buf[pos++] == '\r') break; // if it is followed by a carriage return then it is a blank line (\r\n\r\n)
//    }
//    if (buf[pos])  // we didn't run out of buffer
//    {
//      pos++;  //skip over the '\n' remaining
//      Serial.println((char*)&buf[pos]);
//    }
//  }
}

void setup(){
  Serial.begin(57600);

  /*initialize enc28j60*/
  es.ES_enc28j60Init(mymac);

  //init the ethernet/ip layer:
  es.ES_init_ip_arp_udp_tcp(mymac, myip, PORT);

  // init the web client:
  es.ES_client_set_gwip(gwip);  // e.g internal IP of dsl router

}

void loop()
{
  static uint32_t timetosend;
  uint16_t dat_p;
  int sec = 0;
  long lastDnsRequest = 0L;
  int plen = 0;
  int reqsent = 0; // flags the request sending
  int streamon = 0; // flags the streaming

  dns_state=0;

  while(1) {
    // handle ping and wait for a tcp packet - calling this routine powers the sending and receiving of data
    plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
    dat_p=es.ES_packetloop_icmp_tcp(buf,plen);
    if( plen > 0 ) {
      // We have a packet     
      //Serial.println("Packet received"); // debug
      // Check if IP data
      if (dat_p == 0 && reqsent == 0) {
        if (es.ES_client_waiting_gw() ){
          // No ARP received for gateway
          continue;
        }
        // It has IP data
        if (dns_state==0){
          sec=0;
          dns_state=1;
          lastDnsRequest = millis();
          es.ES_dnslkup_request(buf,(uint8_t*)WEBSERVER_VHOST);
          continue;
        }
        if (dns_state==1 && es.ES_udp_client_check_for_dns_answer( buf, plen ) ){
          dns_state=2;
          es.ES_client_set_wwwip(es.ES_dnslkup_getip());
        }
        if (dns_state!=2){
          // retry every minute if dns-lookup failed:
          if (millis() > (lastDnsRequest + 60000L) ){
            dns_state=0;
            lastDnsRequest = millis();
          }
          // don't try to use web client before
          // we have a result of dns-lookup
          Serial.println("DS lookup failed");
          continue;
        }
      }
      else
      {
        if (dns_state==1 && es.ES_udp_client_check_for_dns_answer( buf, plen ) ){
          dns_state=2;
          es.ES_client_set_wwwip(es.ES_dnslkup_getip());
        }
      }
      if (dat_p == 0 && reqsent == 1)  // case where data was received
      {
       
        // case where the request was sent previously and we keep receiving data
        if ( dns_state == 2 && reqsent == 1)
        {
         
          if (streamon==0) // here the stream has not started yet
          //The stream data starts after a double linefeed (0x0a 0x0d 0x0a 0x0d), so we need to find that first
          {
            uint16_t pos = 54;  // we start at 54 bytes, that falls just after the minimum TCP header
            while (pos<=plen)    // loop until end of buffer (or we break out having found what we wanted)
            {
              while (buf[pos]) if (buf[pos++] == '\n') break;   // find the first line feed
              if (pos>plen) break; // run out of buffer
              if (buf[pos++] == '\r') // if it is followed by a carriage return then it is a blank line (\r\n\r\n)
              {
                pos++;  //skip over the '\n' remaining
                if (pos>=plen) continue; // if there are no data, wait for the next packet
                streamon = 1; // if the data is there, yeepee ! start the streaming officially
                while (pos<=plen) // write the remaining data to the buffer
                {
                  Serial.print(buf[pos]); // could use pos++, need to see that later
                  pos++;
                }
                continue;
              }
            }
          }
          else // if we are here, the streaming has already started and we just copy the data
          {
            for (int ii=dat_p+54;ii<plen;ii++)
            {
              Serial.print(buf[ii]);
            }
          }
         
          // need acknowledgement ?
          //es.ES_enc28j60PacketSend(plen,buf);
        }
       
      }
    }
    // If we have IP address for server and its time then request data

    if( dns_state == 2 && reqsent == 0 && millis() - timetosend > 31000)  // every 31 seconds
    {
      timetosend = millis();
      // note the use of PSTR - this puts the string into code space and is compulsory in this call
      // second parameter is a variable string to append to HTTPPATH, this string is NOT a PSTR
      es.ES_client_browse_url(PSTR(HTTPPATH), NULL, PSTR(HOSTNAME), &browserresult_callback);
      reqsent = 1; // data sent, so flag up
    }   
  }
}


Now, I have a problem with the rMP3: I cannot connect it. I remember having that problem before, but I don't remember how I solved it. Basically, when I load a basic rMP3 script, the program stops when it tries to use the rmp3 object. For instance, it stops when calling rmp3.getmoduletype().
I tried to change the baudrate, but it does not make a difference. I don't understand where the problem is...
Title: Re: Ethernet MP3 Player
Post by: bhagman on Apr 17, 2011, 06:21 pm
@LB01: Which Arduino board are you using?  Can you post the code you used to connect to the rMP3?
Title: Re: Ethernet MP3 Player
Post by: LBArduino on Apr 18, 2011, 07:49 pm
Well, the issue resolved on its own. I am not sure of what I did but now it works. I was probably confused with the baudrates. For info, I am using the arduino demilanove, with atmega 328.

Anyway, I tidied up the code and I regrouped all the writing operations in one callback (fillsdbuffer). If you just leave the serial.print operation in this function, and you remove all the operations on the rMP3, this code sends the stream to the serial port, ready to be read.

The problem I have now is that, when I added the rMP3 code, I could not open the file /buf1 where I plan to write the stream (line 108). Is there anything obviously wrong?

Here is the code:

Code: [Select]

/*
* Stores a stream on the SD card, in buffer 1 (/stream/buf1)
*/
# define WWW_client

#include <EtherShield.h>
#include <NewSoftSerial.h>
#include <RogueMP3.h>
#include <RogueSD.h>

static uint8_t mymac[6] = {0x54,0x55,0x99,0x10,0x00,0x25};
static uint8_t myip[4] = {192,168,1,1};
// Default gateway. The ip address of your DSL router. It can be set to the same as
// websrvip the case where there is no default GW to access the
// web server (=web server is on the same lan as this host)
static uint8_t gwip[4] = {192,168,1,254};

//=========================== =================================================================================
// Website declarations
//============================================================================================================
#define PORT 80                   // HTTP

// the etherShield library does not really support sending additional info in a get request
// here we fudge it in the host field to add the API key
// Http header is
// Keep-Alive: 330
// Host: mp3.live.tv-radio.com
// User-Agent: Arduino/1.0
// Accept: text/html
#define HOSTNAME "mp3.live.tv-radio.com\r\nKeep-Alive: 300"      // API key
static uint8_t websrvip[4] = { 0,0,0,0 }; // Get pachube ip by DNS call
#define WEBSERVER_VHOST "mp3.live.tv-radio.com"
#define HTTPPATH "/franceinter/all/franceinterhautdebit.mp3"      // Set your own feed ID here

static uint8_t resend=0;
static int8_t dns_state=0;

EtherShield es=EtherShield();
#define BUFFER_SIZE 900
static uint8_t buf[BUFFER_SIZE+1];

// setting the rMP3
NewSoftSerial rmp3_serial(6, 7);
RogueMP3 rmp3(rmp3_serial);
RogueSD filecommands(rmp3_serial);
char path[96];  // path of the buffers
uint8_t volume = 40; // sound volume
#define SD_BUFFER_SIZE 128000 // size of each buffer on the SD card


void browserresult_callback(uint8_t statuscode,uint16_t datapos){
// left here in case it is needed later
}

// fillsdbuffer transfers the data from the ethernet buffer to the SD cards
// fillsdbuffer( ethernet buffer, starting position, ending position,
//               SD buffer handle, current SD position)
void fillsdbuffer(uint8_t *buf, int pos, int plen, uint8_t filehandle, uint16_t sdpos){
 
 char s;
 while (pos<=plen) // write the remaining data to the buffer
 {
   s = char(buf[pos]);
   filecommands.write(filehandle,1,&s);
   Serial.print(buf[pos]); // could use pos++, need to see that later
   pos++;
   sdpos++;
 }
                   
}

void setup(){
 Serial.begin(230400);

 /*initialize enc28j60*/
 es.ES_enc28j60Init(mymac);

 //init the ethernet/ip layer:
 es.ES_init_ip_arp_udp_tcp(mymac, myip, PORT);

 // init the web client:
 es.ES_client_set_gwip(gwip);  // e.g internal IP of dsl router
 
 rmp3_serial.begin(9600); // parameter D3 in the RMP3.CFG config file (root dir)
 
 rmp3.sync();
 rmp3.stop();
 rmp3.setvolume(volume);
 filecommands.sync();
 
}

void loop()
{
 static uint32_t timetosend;
 int pos;
 int dat_p;
 int sec = 0;
 long lastDnsRequest = 0L;
 int plen = 0;
 int reqsent = 0; // flags the request sending
 int streamon = 0; // flags the streaming
 int8_t filehandle; // handle to the active SD buffer
 uint16_t sdpos = 0; // position of last data in the SD  buffer
 dns_state=0;

 // open the 1st SD buffer, directory /stream/
 filehandle = filecommands.open("/buf1",open_mode(OPEN_WRITE));
 if (filehandle<1) // in case of an error during the opening
 {
   Serial.println("Error: cannot open the file.");
   while (1) {}; // stops here, cannot continue anyway.
 }

 while(1) {
   // handle ping and wait for a tcp packet - calling this routine powers the sending and receiving of data
   plen = es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf);
   dat_p=es.ES_packetloop_icmp_tcp(buf,plen);
   if( plen > 0 ) {
     // We have a packet
     // Check if IP data
     if (dat_p == 0 && reqsent == 0) {
       if (es.ES_client_waiting_gw() ){
         // No ARP received for gateway
         continue;
       }
       // It has IP data
       if (dns_state==0){
         sec=0;
         dns_state=1;
         lastDnsRequest = millis();
         es.ES_dnslkup_request(buf,(uint8_t*)WEBSERVER_VHOST);
         continue;
       }
       if (dns_state==1 && es.ES_udp_client_check_for_dns_answer( buf, plen ) ){
         dns_state=2;
         es.ES_client_set_wwwip(es.ES_dnslkup_getip());
       }
       if (dns_state!=2){
         // retry every minute if dns-lookup failed:
         if (millis() > (lastDnsRequest + 60000L) ){
           dns_state=0;
           lastDnsRequest = millis();
         }
         // don't try to use web client before
         // we have a result of dns-lookup
         Serial.println("DS lookup failed");
         continue;
       }
     }
     else
     {
       if (dns_state==1 && es.ES_udp_client_check_for_dns_answer( buf, plen ) ){
         dns_state=2;
         es.ES_client_set_wwwip(es.ES_dnslkup_getip());
       }
     }
     if (dat_p == 0 && reqsent == 1)  // case where data was received
     {
       
       // case where the request was sent previously and we keep receiving data
       if ( dns_state == 2 && reqsent == 1)
       {
         
         if (streamon==0) // here the stream has not started yet
         //The stream data starts after a double linefeed (0x0a 0x0d 0x0a 0x0d), so we need to find that first
         {
           pos = 54;  // we start at 54 bytes, that falls just after the minimum TCP header
           while (pos<=plen)    // loop until end of buffer (or we break out having found what we wanted)
           {
             while (buf[pos]) if (buf[pos++] == '\n') break;   // find the first line feed
             if (pos>plen) break; // run out of buffer
             if (buf[pos++] == '\r') // if it is followed by a carriage return then it is a blank line (\r\n\r\n)
             {
               pos++;  //skip over the '\n' remaining
               if (pos>=plen) continue; // if there are no data, wait for the next packet
               streamon = 1; // if the data is there, yeepee ! start the streaming officially
               fillsdbuffer(buf,pos,plen,filehandle,sdpos);
               continue;
             }
           }
         }
         else // if we are here, the streaming has already started and we just copy the data
         {
           fillsdbuffer(buf,dat_p+54,plen,filehandle,sdpos);
//            for (int ii=dat_p+54;ii<plen;ii++)
//            {
//              Serial.print(buf[ii]);
//            }
         }
         
         // need acknowledgement ?
         //es.ES_enc28j60PacketSend(plen,buf);
       }
       
     }
   }
   // If we have IP address for server and its time then request data

   if( dns_state == 2 && reqsent == 0 && millis() - timetosend > 31000)  // every 31 seconds
   {
     timetosend = millis();
     // note the use of PSTR - this puts the string into code space and is compulsory in this call
     // second parameter is a variable string to append to HTTPPATH, this string is NOT a PSTR
     es.ES_client_browse_url(PSTR(HTTPPATH), NULL, PSTR(HOSTNAME), &browserresult_callback);
     reqsent = 1; // data sent, so flag up
   }
   
 }
}



Title: Re: Ethernet MP3 Player
Post by: LBArduino on Apr 23, 2011, 12:44 pm
Ok, I am nearly there, but I have a problem with the rMP3 module. It has problems to sync when the baudrate is different from 9600.
I have tried to include the baudrate change in the code because I first thought that the problem was coming from the SD card. So I start th communication at 9600, change to 57600, ask a confirmation by checking the baudrate parameters from the rMP3 (it gives a '3', indicating that it has changed correctly and it is still woking), and then I use the sync function and the program stops. What is the problem?
I upgraded the rMP3 firmware last December to reduce the latency between two files. Could there be a problem in the new firmware?

Here is the section of code I use for changing the baudrate:
Code: [Select]

Serial.println("starting rmp3");
  rmp3_serial.begin(9600); // default baudrate

  char setbaud = 0x44; //D
  uint8_t baudratecode = 3; //230400: parameter D7 in the config file
  //rmp3.changesetting(setbaud, baudratecode);
  Serial.println(rmp3.getsetting(setbaud));
  rmp3.changesetting(setbaud, baudratecode);
  delay(1000);
  rmp3_serial.begin(57600);
  Serial.println(rmp3.getsetting(setbaud)); // check that everything is fine
 
//  // back to 9600, for debugging purposes (so you don't have to power off the arduino every time)
//  baudratecode = 0;
//  rmp3.changesetting(setbaud, baudratecode);
//  delay(1000);
//  rmp3_serial.begin(9600);
//  Serial.println(rmp3.getsetting(setbaud));
 
  Serial.println("Sync");
  rmp3.sync();
  Serial.println("Stop");
  rmp3.stop();
  Serial.println("Set volume");
  rmp3.setvolume(volume);
  Serial.println("Sync filesystem");
  filecommands.sync();
 
  Serial.println("ready");

Title: Re: Ethernet MP3 Player
Post by: mowcius on Apr 23, 2011, 12:48 pm
Have you tried setting the baud rate with the boot config file on the SD card instead of in code?

http://www.roguerobotics.com/wikidocs/rmp3/documentation/boot_config (http://www.roguerobotics.com/wikidocs/rmp3/documentation/boot_config)
Title: Re: Ethernet MP3 Player
Post by: LBArduino on Apr 23, 2011, 05:45 pm
Yes, I did that first and I could not sync either when I used D5 and D7 as parameters.
Using D0 was not a problem, but 9600 is too low for streaming.
Title: Re: Ethernet MP3 Player
Post by: bhagman on Apr 25, 2011, 07:10 pm
Since you're using the Duemilanove, you won't be able to get much better than 57600 bps on a SoftwareSerial port.  Can you try setting the rMP3 to 38400 bps?  (Setting: "D2")

See if that works.  If it does, you'll have to:

1) use Serial for your communications with the rMP3 (you will have to add jumpers from pins 6 and 7 to pins 0 and 1 - and you will have to remove the rMP3 each time you upload a sketch).

2) use another board which has an extra hardware serial port (e.g. LEDHead (http://www.roguerobotics.com/products/electronics/ledhead), Arduino Mega, etc...
Title: Re: Ethernet MP3 Player
Post by: mowcius on Apr 25, 2011, 09:23 pm
Oh I had forgotten about the Software Serial speed limitations - glad you came to the rescue with answers :D
Title: Re: Ethernet MP3 Player
Post by: LBArduino on Apr 25, 2011, 11:20 pm
ok, so 38400 works for the sync but the stream is corrupted. I suppose the write operation to the SD takes too long at that baudrate.
So I will try to do as bhagman says. I will see if I can go up to 57600 using the serial port. Will I still need the SerialSoftware library?
Title: Re: Ethernet MP3 Player
Post by: bhagman on Apr 26, 2011, 09:51 pm
If you use the hardware serial port, you won't need SoftwareSerial any more.

Just remember that you will have to remove the rMP3 (with power removed) each time you want to upload!  (This only applies when using the same hardware serial port that is used for uploading the sketch).

e.g.

Code: [Select]
#include "RogueMP3.h"

RogueMP3 rmp3(Serial);

void setup(void)
{
  Serial.begin(57600);
  rmp3.sync();

  ...
}


Title: Re: Ethernet MP3 Player
Post by: LBArduino on May 02, 2011, 01:27 pm
I had some spare time to work on that issue.

I soldered a couple of pins to make it easier to connect/disconnect the rMP3. It works well, the only things is that it is confusing that the Tx/Rx pins on the solderable pads must be connected to the Rx/Tx of the arduino serial pins respectively (it must be a crossed cable). Apart from this point, I like this system, it is very flexible.

So I connected everything and modified a simple script to play a tune with the rMP3 using the serial port, and it works very well at 9600 but still fails at 57600. Basically, when I change the option D0 to D3 with the correct serial baudrate, the music does not start. Here is the setup function:

Code: [Select]
void setup()
{
  delay(2000);
  Serial.begin(9600);  // initialise the serial rMP3 connection
 
  rmp3.print("ST D0"); // if changed to D3, the module fails
  delay(100);
  Serial.begin(9600); // that would be changed to 57600
  delay(100);
 
  rmp3.sync();
  rmp3.stop();
  rmp3.setvolume(volume);
 
  filecommands.sync();

  // mix up our random number generator
  randomSeed(analogRead(0));

  updateSongList();
 
}


I suspect that the sync is still a problem. Any suggestion?
Title: Re: Ethernet MP3 Player
Post by: mowcius on May 02, 2011, 02:01 pm
Quote
Code: [Select]
  Serial.begin(9600);  // initialise the serial rMP3 connection
 
  rmp3.print("ST D0"); // if changed to D3, the module fails
  delay(100);
  Serial.begin(9600); // that would be changed to 57600
  delay(100);

You have two 'Serial.begin(####)' lines in there...
Title: Re: Ethernet MP3 Player
Post by: LBArduino on May 02, 2011, 02:37 pm
yes, I use that to set the baudrate to whatever I need. It is not nice, but with that I don't need to change the config file on the SD card everytime I change the baudrate. And it works when I use 9600. It also works when I set 57600 and then come back to 9600.
Title: Re: Ethernet MP3 Player
Post by: bhagman on May 02, 2011, 06:30 pm
The only thing I can see is that you don't send the <CR> to complete the command.

Try this:
Code: [Select]
  rmp3.print("ST D3\r");

Title: Re: Ethernet MP3 Player
Post by: LBArduino on May 02, 2011, 11:57 pm
Thanks a lot, it is now working! I did forget the \r to validate the changes, it seems like my shortcut to change the baudrate created more problems than it solved.

Anyway, I can now see the LEDS flashing on the ethernet shield, so the stream is coming. I can also see the indicator lit on the rMP3 and some data is written on the SD card but it cannot be read when the card is connected to my computer. The data is corrupted somewhere.

I suppose that the write operation is still too long for some reason (the 'Data in' LED of the  ethershield board does not flash very often). At the moment, I am using a byte-by-byte write operation because the stream buffer is a uint8_t and the write methods needs a char. Here is what I was doing:

Code: [Select]

char s;
 while (pos<plen) // write the remaining data to the buffer
 {
   s = char(buf[pos]);
   filecommands.write(filehandle,1,&s);
   pos++;
 }


I replaced it by the following:

Code: [Select]
char s[plen];
  while (pos<plen) // write the remaining data to the buffer
  {
    s[pos] = char(buf[pos]);
    pos++;
    sdpos++;
  }
  filecommands.write(filehandle,plen,s);


but now a red LED starts to flash on the rMP3 when the stream arrives. I suppose that means a buffer overflow because i pass on too much data in one go?



Title: Re: Ethernet MP3 Player
Post by: LBArduino on May 03, 2011, 09:17 pm
Still no luck, I have this red LED flashing on the rMP3 board whatever I try to do. What does this LED means? I can at best write 40 - 60 characters on to the SD card before it starts to flash.
Title: Re: Ethernet MP3 Player
Post by: novice on Aug 08, 2011, 04:44 am
Hi LB01,

I've been quietly watching your project since it began.  It would be such a cool project for the Arduino and the rMP3!.

There's a writeup of a related project DIY MP3/OGG/FLAC music player using Arduino and VS1053 at http://kalum.posterous.com/private/sHqcofxooc that could be worth looking at. It's not strictly playing streaming radio, but the code could give you some ideas.
Title: Re: Ethernet MP3 Player
Post by: LBArduino on Aug 12, 2011, 09:33 pm
Hi Novice,

Thanks for your enthousiasm, to be honest I left this project aside because I could not get any progress.

Using the arduino duemilanove, the rMP3 and an ethreshield, I managed to capture an icecast stream correctly but it could not copy it to the SD card (on the rMP3 board). If I redirect the stream to the USB serial port, it does work! I can listen to the radio, no problem. But as I said, the problem I have now is to copy this stream to the SD card on  the fly and there is a problem with the rMP3 card with that, the write function fails 90% of the time to copy the data. Apart from that, the rMP3 module seems to work fine so I feel like I am close to completion...

Ok, I will try and make it work again, but that will probably need some changes in the rMP3 firmware too.
Title: Re: Ethernet MP3 Player
Post by: bhagman on Aug 26, 2011, 06:06 am
Hey LB01,

I've been thinking this over, and I don't think that using the files will be the best way to go.  I've got a new idea (not really rocket science) to just add a direct serial stream to the decoder.  Should be pretty easy to do.  I'll update you when I get the coding done.

b
Title: Re: Ethernet MP3 Player
Post by: LBArduino on Aug 27, 2011, 06:10 pm
oh great ! I'll be waiting for it!

I just replied to your first email and I sent you the code that I wrote so far, but you may not need to look at it if you develop your idea. At the moment I can get a 128k/s icecast stream without a problem using a baudrate of 230400, but only if I redirect it to the USB port. Copying to the rMP3 SD card fails. If you can manage to make a direct protocol, then I think it will be very straightforward for me to finish.
Title: Re: Ethernet MP3 Player
Post by: frsc on Sep 07, 2011, 04:04 pm
I'm working on a project, that includes the tranferring of audio via ethernet and playback by Arduino.
Therefore I watch the thread with great interest and I hope that you guys might get it working.
Title: Re: Ethernet MP3 Player
Post by: kalum on Sep 12, 2011, 06:54 pm

oh great ! I'll be waiting for it!

I just replied to your first email and I sent you the code that I wrote so far, but you may not need to look at it if you develop your idea. At the moment I can get a 128k/s icecast stream without a problem using a baudrate of 230400, but only if I redirect it to the USB port. Copying to the rMP3 SD card fails. If you can manage to make a direct protocol, then I think it will be very straightforward for me to finish.


The main issue with a ethernet streaming mp3 player is the buffering of data packets. The AVR has only 2k of RAM which is not enough to buffer the TCP/IP packets form the ethernet controlller, buffering is needed as packets form the internet can be corrupted etc, so the ideal setup would be the avr connected to the ethernet controller and additional ram available via a SPI interface. The SPI interface can also be shared with the vs1053 mp3 decoder chip to complete the ethernet based mp3 streaming media player. This kind of setup is seen on the vs1053 page for the PIC family and ARM.

http://www.watterott.net/projects/webradio-arm

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en536047


The key issue is the code to interface the external SRAM to buffer the ethernet packets. If that can be sorted out, you will have your avr based streaming mp3 player :)
Title: Re: Ethernet MP3 Player
Post by: maniacbug on Dec 26, 2011, 06:34 pm

The main issue with a ethernet streaming mp3 player is the buffering of data packets. The AVR has only 2k of RAM which is not enough to buffer the TCP/IP packets form the ethernet controlller.


The VS1053 has a 2K internal memory dedicated to buffering incoming data.  I wonder if that would be enough of a buffer, so I'm going to try this out.  At 160kbps, that buffer holds 100ms of audio, so you've got that long to fill it up with data over the network.  In theory, that should be plenty of time.  It will be interesting to try!