Shop OBEX P1 Docs P2 Docs Learn Events
VS1053 + mSD to run mp3 on its own — Parallax Forums

VS1053 + mSD to run mp3 on its own

ErlendErlend Posts: 612
edited 2014-01-23 19:09 in Propeller 1
To avoid creating all the sounds I need in .wav I had the idea to run mp3 files from a separate board, as instructed through SPI from Prop. Found a nice break-out board at Ada, but maybe I was too fast (again) to add-to-basket, because now I seem to understand that Prop has to do the work of reading SD and feeding into the VS1053 chip. So instead of occasionally shooting off a short 'play file_nnn' SPI command, now a cog is needed to read&write sound data all the time while playing. Will be hard on prop i/o, and will mean a lot of coding to do for me - I already suffer an inbox-overload situation in my life/brain/lab, so this 'household' coding is not something I urge for now.
I searched Obex, but with little luck, so now I ask the Forum for help - maybe someone have already intefaced this breakout board, or at least the VS1053 chip - or maybe there is an other board out there which is doing exactly what I wanted? Or maybe I am wrong about the ada-board - that it can do this after all?

Erlend

Comments

  • localrogerlocalroger Posts: 3,451
    edited 2014-01-19 06:58
    I checked the data sheet and yeah, that's a typical MP3 codec which needs something else to extract the bitstream from the SD card filesystem and send it to the codec. Presumably the Arduino library includes the file system drivers. For the Propeller you'd need fsrw or something similar to open and read the sound file.

    A better choice for what you're trying to do would be the Daisy player kit, which includes a PIC uC to read the card and simple inputs to trigger playback:

    http://www.teuthis.com/daisy/

    Or, a bit fancier, smaller, more capable, and pre-assembled, Rogue Robotics uMP3:

    http://www.roguerobotics.com/products/electronics/ump3

    If you'd like to see an example of a Propeller controlling a similar codec, Harrison Pham's award-winning Thumper does this as well as a lot of other cool network streaming stuff:

    http://classic.parallax.com/Thumper/tabid/848/Default.aspx
  • T ChapT Chap Posts: 4,223
    edited 2014-01-19 07:15
    If using a USB drive is ok, look up the Vmusic2, it is very easy to drive from simple serial commands from the Prop. VS1033 and Vinculum does the hard work.
  • ErlendErlend Posts: 612
    edited 2014-01-20 01:39
    Thanks, very good info!
    I will put the ada-player in a drawer for some future project. Both the uMP3 and the Vmusic2 fit my purpose perfectly, but I think I will go for the Vmusic because - I did not think about that before - the USB stick is a more convenient format in this application. The interface looks dead simple, with SPI or serial, and a easy command set.

    Erlend
  • T ChapT Chap Posts: 4,223
    edited 2014-01-20 02:42
    If you get the VMusic2, here are some examples:

    PUB Speak(n)
        case n
            0  : ser.str(2, string("VPF 0.mp3", CR))
                 waitcnt(40_000_000 + cnt)
            1  : ser.str(2, string("VPF 1.mp3", CR))
                 waitcnt(40_000_000 + cnt)
            2  : ser.str(2, string("VPF 2.mp3", CR))
                 waitcnt(40_000_000 + cnt)
    
    
    PUB SayNumber(num)    |  x, y, z  'will not say '0'  ???
        Silence
        VolUP
        x := (num/100) * 100
        y :=  ((num/10) // 10)  * 10
        z := num // 10
        If (y+z) > 9 AND (y+z) < 20
           z := y + z
           y~
        if x > 0
          Silence
          VolUp
          speak(x)
          waitcnt(40_000_000 + cnt)
    
        if y > 0
          Silence
          VolUp
          speak(y)
          waitcnt(40_000_000 + cnt)
    
        if z == 0
          if x == 0 AND y == 0
            Silence
            VolUp
            speak(z)
    
        if z > 0
            Silence
            VolUp
            speak(z)
    
    
    PUB SetVol
        ser.str(2, string("VSV"))
        ser.tx(2, $20)
        ser.tx(2, VoiceVol)
        ser.tx(2, $0D)
    
    
    
    
    PUB Set1033Rate
        ser.str(2, string("VWR"))
        ser.tx(2, $20)
        ser.tx(2, $05) 'sample rate
        ser.tx(2, 44101)
        ser.tx(2, 44101 >> 7)
        ser.tx(2, $0D)
    
    
    PUB Set1033Mode           ''unused    should be vwr?
        ser.str(2, string("VRD"))     '''v read
        ser.tx(2, $20)
        ser.tx(2, Mode)  '''MODE=$00, VOL=$0B, STATUS=$01, audata/RATE=$05, BASS=$02
        ser.tx(2, Mode >> 8)
        ser.tx(2, CR)
    
    
    PUB Set1033Bass
        ser.str(2, string("VWR"))
        ser.tx(2, $20)
        ser.tx(2, $02) 'bass
        ser.tx(2, 1111_1111)   ' bass15 14 13 12         booost   1-15   ..   freq
        ser.tx(2, 0001_0001)   'trebel  7654  boost/cut  -8..7  0 = off  ...   freq
        ser.tx(2, $0D)
    
    
    PUB VolON
        ser.str(2, string("VSV"))
        ser.tx(2, $20)
        ser.tx(2, 00)
        ser.tx(2, $0D)
    
    
    PUB VolOFF
        ser.str(2, string("VSV"))
        ser.tx(2, $20)
        ser.tx(2, 100)
        ser.tx(2, $0D)
    
    
    
    PUB ReadFile(readlen)
           'rd4 := readlen >> 24
           'rd3 := readlen >> 16
           'rd2 := readlen >> 8
           'rd1 := readlen
    
           'ser.str(2, string("RDF"))
           'ser.tx(2,$20)
           'ser.tx(2,rd4)
           'ser.tx(2,rd3)
           'ser.tx(2,rd2)
           'ser.tx(2,rd1)
           'ser.tx(2,$0D)
    
    
    PUB OpenFile(filename)
        'ser.str(2, string("OPR"))
        'ser.tx(2, $20)
        'ser.str(2, filename)
        'ser.tx(2, $0D)
    
    
    PUB CloseFile(cfname)
        'ser.str(2, string("CLF"))
        'ser.tx(2, $20)
        'ser.str(2, cfname)
        'ser.tx(2, $0D)
    
    Pub Seek(s)         'seek to a specific location within an already open for read file
          'sekval := s     'sekval is long, destination to seek for read start
          'go(0,0)
          'ser.hex(3, sekval, 4)
          'sek4 := sekval >> 24
          'sek3 := sekval >> 16
          'sek2 := sekval >> 8
          'sek1 := sekval
          'ser.str(2, string("SEK"))
          'ser.tx(2,$20)
          'ser.tx(2,sek4)
          'ser.tx(2,sek3)
          'ser.tx(2,sek2)
          'ser.tx(2,sek1)
          'ser.tx(2,$0D)
    
    
    PUB OpenFileToWrite(filename)    'open or create file
        ''''ser.str(2, string("OPW"))
        'ser.tx(2, $4F)  'O
        'ser.tx(2, $50)  'P
        'ser.tx(2, $57)  'W
    
    
        'ser.tx(2, $20)
        'ser.str(2, filename)
        'ser.tx(2, $0D)
    
    
    PUB WriteFileSize(size)      '4 bytes specifies size of data to follow in WriteData
        'wr4 := size >> 24
        'wr3 := size >> 16
        'wr2 := size >> 8
        'wr1 := size
        'ser.str(2, string("WRF"))
        'ser.tx(2,$20)
        'ser.tx(2,wr4)
        'ser.tx(2,wr3)
        'ser.tx(2,wr2)
        'ser.tx(2,wr1)
        'ser.tx(2,$0D)
    
    PUB WriteData(size, pointer)  | g, o    'send the data part of WriteFile
        'g~
        'repeat size
          ''''ser.tx(2, testbyte[g])
          'ser.tx(2, byte[pointer][g])
    
          'g++
        'ser.tx(2,$0D)
    
    
    
    PUB readusb(size)   |  m, v, t, check
         't~
         'w(500_000)   'delay required else usb hangs
         'm~
         'Repeat until t == size          '<<<<<warning flag  leave at 64
           'v :=  ser.rxtime(2, 200) '   (z, 100)   'read more, port 0, wait 2 ms if no byte
           'If v == -1
             'Return  -1
           'ResponseArray1[m] := v
           'm++
           't++
           'if check < 54 'detect/remove previous vinculum response left overs if below first 54 bytes
            'if  ResponseArray1[m - 3] == $5C   'vinc left over info string
             'if  ResponseArray1[m - 2] == $3E   'vinc left over info  string
               'if  ResponseArray1[m - 1] == $0D  'vinc left over info  string
                 'm~              'reset all if old string rec'd
                 't~              'reset all if old string rec'd
                 'check~          'reset all if old string rec'd
           ''''''w(100000)
           'check++
    
    
    PUB ReadFileFromUSB(size, startaddr, filename)  'how to set to read if above 64bytes?
         ''''if size is greater than current file size, device pads FE
         'ser.str(3, filename)
         'OpenFile(filename)
         'if startaddr > -1
            'seek(startaddr)
         'ReadFile(size)  'read the file  at start, using readsize
         'readusb(size)
         'WritePage(eeprom1, eepromwriteindex, @ResponseArray1, size)     'always store to eeprom1?
         'CloseFile(filename)
    
    
    PUB TestUSBReadWRite
         'WriteFileToUSB(8, 0,string("logger"))
         'waitcnt(40_000_000 + cnt)
         'ReadFileFromUSB(8, 0, string("logger"))
    
    
    PUB VStop
        ser.str(2, string("VST", CR))
        ser.tx(2, $0D)
    PUB VoiceIntro
         Silence
         Volup
         ser.str(2, string("VPF 1005.mp3", CR))
         'Fade  
    
    PUB VolUp
        ser.str(2, string("VWR"))
        ser.tx(2, $20)
        ser.tx(2, $0B)
        ser.tx(2, VoiceVol) 'left
        ser.tx(2, VoiceVol) 'right   or vice versa?
        ser.tx(2, $0D)
    
    PUB Reset   'stop playing audio
        ser.str(2, string("VWR"))
        ser.tx(2, $20)
        ser.tx(2, $00)
        ser.tx(2, ResetMode)
        ser.tx(2, ResetMode >> 8)   'jump out of wave decode
        ser.tx(2, $0D)
    
    PUB Mute
        ser.str(2, string("VWR"))
        ser.tx(2, $20)
        ser.tx(2, $0B)
        ser.tx(2, $FE) 'left
        ser.tx(2, $FE) 'right   or vice versa?
        ser.tx(2, $0D)
    
    PUB Silence
        Mute       'change to fast fade vol off, might be smoother
        Vstop
        Reset
    
    
  • ErlendErlend Posts: 612
    edited 2014-01-20 03:05
    I think I will, but I found some old warnings on the net - along with the solutions to the problems.
    Thanks a bunch for the code!

    Erlend
  • T ChapT Chap Posts: 4,223
    edited 2014-01-20 03:13
    I never bought one, I built a board from the exact same schematic and never had a problem, but it seems there were people that had problems, specifically jumper settings if I recall. I believe that in the early days there was an error in the data sheet or on the schematic that made it hard to get going, so most people went to the SD card. I always program the Vinculum with the Vrog utility and the music firmware. I can't imagine FTDI would still be selling something if it still had the same high rate of complaints.

    Another SD option:

    https://www.sparkfun.com/products/11029
  • ErlendErlend Posts: 612
    edited 2014-01-20 05:52
    It looks to me it all relates to unclear/incomplete documentation. Would have been a horror in the old days, but in the days of Internet info can always be found. Wonderful times!
    I will buy one! (two, actually).

    Erlend
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2014-01-20 07:27
    Sparkfun's MP3 player board (a shield for the Arduino but easily adaptable to anything else) is much cheaper than the Rogue Robotics board, and includes the SD card slot. If an Arduino can be used for this, certainly a Propeller can. The VLSI chip takes data in bursts, buffering in between, so even on an Arduino there's a little bit of time for other processing tasks -- depending on the bit rate of the MP3 file. There are entries in the Obex for reading SD cards through SPI, and doing various file service tasks.

    That said, if you're wanting to do much more with any processor you're probably better off getting an all-in-one. The VMusic module is one choice, but there's also others, such as the MP3 Trigger board Sparkfun sells. I've used it and it's painfully easy.
  • WBA ConsultingWBA Consulting Posts: 2,934
    edited 2014-01-20 10:35
    Similar details on this thread with a few products worth checking out. Also, this may be the one I end up going after: http://www.seeedstudio.com/depot/garan-audio-module-p-1607.html
  • Tim-MTim-M Posts: 522
    edited 2014-01-20 11:01
    +1 for the MP3 Trigger through SparkFun Electronics... full of features, easy to use and priced very reasonably. Great product by audio professional Jamie Roberts that's stand alone turn-key, or ready for most any micro-controller!

    https://www.sparkfun.com/products/11029

    Tim
  • ErlendErlend Posts: 612
    edited 2014-01-20 22:59
    I have already ordered the Vmusic from Mouser. It's the most versatile yet simple I believe, and I do like the packaging. Price is stiff, though.

    Erlend
  • localrogerlocalroger Posts: 3,451
    edited 2014-01-23 19:09
    Sparkfun's MP3 player board (a shield for the Arduino but easily adaptable to anything else) is much cheaper than the Rogue Robotics board, and includes the SD card slot.

    To be clear, both Daisy and Rogue Robotics uMP3 have SD sockets and are entirely self-propelled, needing just a command to start playing a song. The uMP3 has its SD socket on the back of the card to make the card smaller. Daisy can be set up to be even simpler to control, where just a pulse or contact closure will trigger playback of an entire song. While all the tools are there to drive a MP3 codec chip from the Propeller, the SD card filesystem will eat a good chunk of Hub RAM just to get the bits out of the file in order.
Sign In or Register to comment.