WAV sound file player

Last night my Propeller WAV player played its first flawless performance! A full 50 seconds of smooth, clear audio!

It's still very much under construction but I'd like to present the first working version.

This reads a standard WAV file, by name, from an SD card and plays it. It will directly drive a set of mini headphones, or can be sent to amplified computer speakers for louder sound.

Currently it only plays single channel 8 bit PCM (raw digitized byte) files. I've tested it on 8, 11.25, 16 and 22 kHz, all of which
work. It does play 16 bit files but there is a bug that creates bad static in the audio; still working on that. It should be able to play 2 channel (stereo) but I haven't added a second DAC circuit.

It reads short filenames, only, from the root directory of a FAT16 filesystem. It can read FAT12 files but can't play them. I hope to add the ability to search subdirectories for files but probably won't bother decoding long filenames or FAT12 WAV files.

Architecture - the card Spin object starts an assembly cog that manages the SD card. Spin sends sector read requests to asm and reads filesystem info, searches the FAT16 root directory for requested files by name, reads the header from the located WAV file and decodes WAV parameters. Then Spin requests the card asm to read and export the file data.

The card assembly cog reads sectors of file data and passes the data to hub variables. The assembly does the complete FAT16 file tracking, managing clusters, sectors, reading the FAT table to locate the next cluster of the file, and reads sectors until the end of the file. The card module streams file data to a standard output interface, which could be used for other purposes, such as an ebook text display, something else I'd also like to do someday.

The card Spin then starts the DAC asm cog, passing it the address of the card data transfer variables (and the WAV parameters.) The DAC cog configures itself for the data rate, number of bits, then reads data and plays it via the CTRB FRQ controlled IO bit. From that point on, the card and DAC cogs are running on their own, independently from the calling Spin cog, with one producing data and the other consuming it. The DAC cog plays until no more data is available.

The trickiest part was that the DAC cog has to buffer a large supply of sound samples to bridge the times that the card cog pauses to read another sector, and even worse, when a new cluster is needed, to read both a FAT sector then a data sector. Until the buffering was right, the sound played with a regular series of pops, but now it's soft and smooth!

The reason it won't play FAT12 is that the entire FAT file storage cluster decoding is done in assembly to get the speed needed to deliver data fast enough. I did actually get a FAT12 assembly version working, but it was much trickier than FAT16 and basically took up too much code space, to the point where I was fighting for every available byte. I'm not a coding guru; this is all beginner or intermediate-level coding, and the FAT12 struggle was too much. Besides, only smaller SD cards use FAT12; I'm working with a 1 gig SD card and don't expect to go back to 8 meg FAT12 cards.

I'm thinking of using this to make general purpose talking output, like a voltmeter or frequency counter that speaks what it's measuring, or a telescope positioning board that speaks the direction the scope is pointing. Since this will readily play WAV files created by·the PC sound recorder, it's easy to make new sound modules this can play, so those uses aren't that far away!

The SD card data file data stream may be a good fit for the sound decoder players like in the Hydra project; I'm anxious to see how that project works out.



  • 18 Comments sorted by Votes Date Added
  • edited September 2006 Posts: 0Vote Up0Vote Down
    Well done, I am glad to see you have wav files playing off SD as this was one of the things I was in the middle of doing as part of a voice recording device and also a general-purpose O/S thing. Unlike a lot of other processor group forums I can see that most people here are willing to dive in and have a go at it themselves and share. This is in contrast to those other groups where many do not have a single clue and want other people to do it for them.

    Having done this before on other processors I found it straightforward enough to create a 1K buffer comprised of two contiguous 512 byte buffers that are initially filled from the wav file. As the playback routine plays the last entry in a 512 byte buffer it sets a flag for a relatively low-priority task to go and read another sector into this exhausted buffer and reset the flag. The same happens with the second buffer etc and all that the playback routine has to worry about is playing the two 512 byte buffers as if they were a wrap-around 1K buffer and set those flags at the end of each 512 bytes. For 8-bit samples at 11K it takes around 46ms to play 512 bytes and even 16-bit samples is only half that. The biggest problem I find is that the Propeller does not have dedicated high-speed SPI (wouldn't that be nice) and so the bitbanging method is rather slow.

  • edited September 2006 Posts: 0Vote Up0Vote Down
    Good work David. I remember you talking about this project before.
    I'm glad to see you pulled it off so well.

    My ADPCM engine works well for playing back compressed wavefiles but has a 32k limit since it only plays from HUB ram. It compresses about 6 to 1. So 16k of sample space becomes 96k.

    Your engine will be a lot more useful for people who need something that supports A LOT of samples!
    Eitherway I love what you did. Good work!
  • edited September 2006 Posts: 0Vote Up0Vote Down
    David: That's brilliant work yeah.gif . It's something I've had in mind for a project I'm working on, but hadn't a clue where to start. Keep up the good work.

    Peter: Whilst I can see your point, and agree that this is one of only two forums I frequent where people readily dive-in and share code (the other's http://www.picbasic.org/forum/), I am one of those that doesn't have the guru abilities like yourselves (Please don't take this the wrong way). I'm constantly amazed, and in awe of, the stuff that many are able to do here - and each post I read gets me a little closer to doing real stuff with the PChip.

    It will give me enormous satisfaction to one day be able to contribute major code such as this, and I try to be of help where I can, but until that day please bear in mind that us newbies need to stand on the shoulders of giants such as yourselves blush.gif .



    Post Edited (simonl) : 9/29/2006 11:52:29 AM GMT
  • edited September 2006 Posts: 0Vote Up0Vote Down
    Looks nice, but I wonder three things right now. (I haven't get my propeller yet, maybe next week.)

    1. How do you connect the card to the propeller without soldering on the SD-card, can you submit a picture?
    2. Can you post a wiring sheme to the sd-card from the propeller, witch pins on the prop go to wich pins on the SD-card.
    3. Does MMC-cards work? I've got a 32 MB MMC card that i should like to use with the prop.

    Check out my game page: http://maze3d.no-ip.org (Swedish only, sorry.)
  • edited September 2006 Posts: 0Vote Up0Vote Down
    1) Yes by using a socket, such as the one on this page http://www.sparkfun.com/commerce/product_info.php?products_id=204

    2) click on the SD socket under related items, on that page there are several links explaining the interface.

    3) yes SD cards are typically acessed via the SPI interface, which MMC cards also support.

    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • edited September 2006 Posts: 0Vote Up0Vote Down

    Sparkfun......Hey I go there a lot......

  • edited September 2006 Posts: 561Vote Up0Vote Down
    Hi Filip,

    Paul's right; I used an MMC/SD socket. I got mine from Mouser electronic supply, but any should work, and they're inexpensive. (I first experimented with MMC cards by shoving one into a circuit board edge connector, which worked, but was so clumsy I can't recommend this method to anyone.)

    If you search this forum thread for "MMC" you'll see an earlier entry I posted containing a picture of my homemade board with a card in the socket.

    In my included code, at the top of the file utilities.spin, I describe the card-to-propeller wiring. It does take some digging into SD card published documents to determine which SD socket pin needs gnd, and +3.3V, and which go to the Propeller chip, but if you get that far, I can forward the documents which helped me. Also, some pins use a pull-up resistor which I don't think I documented. I'll put together a complete wiring schematic for this card pretty soon and post it.

    I originally wrote this code for the MMC card. Later, I added SD capability, but kept the codes which detect which card is inserted and initialize accordingly. So my code as posted will auto-detect MMC vs. SD and will work equally well with either. They do have different initialization calls; so they do need explicit detection and the proper initialization. But once initialized, they appear to work exactly the same, at least via SPI mode which I use.

  • edited October 2006 Posts: 0Vote Up0Vote Down
    Has anyone considered doing a codec for the speex? It's becoming popular with other embedded processors and seems like a natural for the propeller.

  • edited October 2006 Posts: 0Vote Up0Vote Down
    I've downloaded your waw-player, but i dont get it to work. I'm using the Propeller Demo Board, so I can't use pins 8-12, I've tried to change them to 0-3, but it doesn't work. In how many places in the code do I need to change? I changed in one place.

    I also wonder if it can play large files(about 1 MB).

    Check out my game page: http://maze3d.no-ip.org (Swedish only, sorry.)
  • edited October 2006 Posts: 0Vote Up0Vote Down
    I got it work!

    But it only plays about a half secound of my files and then there comes a noise!
    I use quite large files( the largest is about 4 MB), does the program manage to play that large files to the end?

    Can i you post one of the files you used so that I can test?

    Check out my game page: http://maze3d.no-ip.org (Swedish only, sorry.)
  • edited October 2006 Posts: 561Vote Up0Vote Down
    Hi Filip,

    Congratulations for getting some sound!·

    Are you using my card cog code? And my DAC code?

    The code as posted was really still in the beginnings of development and does have several problems, so it's not surprising that it may fail. But on my hardware it did play about a minute of 8 bit, mono, 22 kHz successfully.

    I'll post my current code, in case it may help. This version has played a full-length song from a music CDROM, 28 megabytes of 16 bit, two channel 44 kHz.

    This newer code is also still under development and isn't clean and polished code, but it does have some improvements and bugfixes:

    It locates and reads the "data" chunk of the WAV file and gets the actual declared data size (but doesn't use that yet to decide when to stop playing).

    It detects whether the WAV file is mono or stereo and manages two DAC channels accordingly. (I added a second DAC channel to my hardware, and upped my clock from 4 to 5 mHz).

    It sets the intersample delay directly from CLKFREQ rather than depending on a hardcoded clock value. For MMC cards, I'd been slowing the propeller down with a CLKSET call to initialize the MMC at a low speed, as per the MMC spec, then using CLKSET again to get back to top speed, but issuing the CLKSET calls seemed to destroy the value of CLKFREQ. So I stopped making the CLKSET calls, and now CLKFREQ may be used to automatically generate the proper DAC delay based on the WAV speed parameter. SD cards seem to initialize fine without that clock slowing during card initialization.

    The DAC code tries to decode the two's complement 16-bit encoding, and it succeeds well enough to play 16 bit sound, but the sound is not so good, so I'm wondering if there is a bug in how I did the 16-bit two's complement-to-unsigned conversion.

    In this code archive, I've also included an 8-bit mono 22 kHz speech sample I got from the internet that should play successfully. Two WAV tests you can do are in your Windows box, right-click on this WAV file and select properties, summary, and Windows should display the WAV parameters. Make sure it shows 8 bit 22 kHz mono. Then let Windows play the file in the Windows Media player or any sound program to verify that the sound file is healthy.

    My code still has problems managing the delays in the DAC part. While it is waiting for the time to play the next sound sample, it tries to calculate whether there is enough time to RDLONG more longs of data from the hub to add to the local data buffer. The trouble is if it doesn't calculate the delays right, WAITCNT will delay a full minute or so as the cog counter rolls over past the wait value. The DAC player will be silent for a long time, then will blast a short noise, then be silent again for a while.

    This is most likely to happen when the SD card reader has reached the end of a FAT filesystem cluster and has to read a FAT sector to locate the next file sector. For 22 kHz, that works out to 45 microseconds per sample, 23 milliseconds per sector, and if your card has 8 sectors per cluster, then you'd get about 0.186 seconds of sound, then silence for a minute, then another short blast of sound. Maybe that's what you're seeing. A test of this is to let the project sit for a full minute or two and see if it does eventually emit another blast of sound.

    That delay code needs some close attention to redesign its timing, but I just haven't gotten to it yet. Lately I've been too busy with work and family activities to put much time into this project. If and when I get it more fine-tuned, I'll post the working code. Or maybe you could fix it?

    But good luck with it! When this project does work, it can produce excellent sound.

  • edited October 2006 Posts: 0Vote Up0Vote Down
    How can I stop the playing of a file and then play another one. I've tried with cogstop(on the cardcog and the daccog). It stops, but I can't play another one then.

    Check out my game page: http://maze3d.no-ip.org (Swedish only, sorry.)
  • edited October 2006 Posts: 561Vote Up0Vote Down
    Hi Filip,

    Congratulations for the progress that you've made!

    I haven't gotten that to work, either.

    Ideally I'd like to have the DAC cog play sound samples while there is input, and simply wait for another set of samples while there is no input, and to have the card cog deliver data to the end of a file, then return to waiting for a user command when done.

    But I just haven't developed this project to that point yet. Something doesn't end properly at the end of a song. I've put a little time into trying to fix it, but had to put it aside. I've been really busy at my home and my work, and not had the time to even look at the project for several weeks now, and I'm not sure when I will get time to work on it again.

    I want to get to it; I've had a great idea about playing a sound effect of an oncoming train, distributed over several speakers with time delays to simulate the train passing by, that will require sampling a WAV file at several points simultaneously. If I ever get to work on this idea, I'll clean up the DAC and the card cog codes to properly end.

  • edited March 2010 Posts: 0Vote Up0Vote Down
    Well it is very great that it is working clearly .. I would like to use that... Can you tell me where do i be able to download it..?

  • edited March 2010 Posts: 0Vote Up0Vote Down
    2 posts above....

    1 Parallax Propeller Robot Control Board
    1 Memsic MX2125 accelerometer/ tilt
    1 Parallax Ping))) ultrasonic sensor

    a few motors and a whole lot of chaos!
  • edited March 2010 Posts: 0Vote Up0Vote Down
    Didn't Kye already post a working wav-player recently?

    PS: found·it http://forums.parallax.com/showthread.php?p=879834·, so , what's the difference?

    Post Edited (MagIO2) : 3/18/2010 7:51:54 AM GMT
  • edited March 2010 Posts: 561Vote Up0Vote Down
    Hi Damon. I worked on this a long time ago.

    Unless there's a particular reason to use this version, I'd suggest using more recent WAV players.

    Rayman and others have posted WAV players in the object exchange, and Kye has worked on a more general WAV player - have you tried those? Would they suit what you're trying to do?
Sign In or Register to comment.