Published using Google Docs
( WAVEPLAY.fth )
Updated automatically every 5 minutes

TACHYON

: WAVEPLAY.fth        ." Singe cog bufferless bare-metal SD card wave player  - 121107.1500-121226.0000 " ;

{

            *** WAVE PLAYER  ***

Single non-dedicated cog SD card wave player that takes 11.025kHz 16-bit signed mono wave files

The PLAY word takes 65 code bytes and does not need any buffers or variables

Reads and plays directly from the SD card using multiple block read mode on the same cog

Assumes file is non-fragmented (normal for SD cards)

External file system must locate the virtual address and size and pass this to PLAY

Use a standard RC filter for the output pin. I use 220R and 0.1uF.

Notes: This is a really barebones wave player showing how simply it can be without having to touch an ounce of assembler.

Tachyon is fast enough to pull this one off and smoothly too. Of course a lot of little extras can be added to this quick hack

but it serves it's purpose and keeps it very simple.

RUNMOD is actually the instruction for SPIO (input and output) when the SPIO module is loaded

If you want a sample wave file to try out then here is one that's a mono 11.025kHz signed wave file "POPCORN.wav"

}

: PLAY ( addr blocks rate pin -- )

     \ A DUTY APIN                               \ audio dac using counter A in duty mode

      A 7 CTRMODE DUP APIN 1+ BPIN                         \ (use this instead if you want stereo outputs)

      ROT #18 CMD 0=                            \ Issue a multiple block read command (also loads SPIO module)

      IF RES@ DROP                                \ when ready

          CLKFREQ SWAP / DELTA                  \ sample period

            FOR                                   \ for multiple blocks - read samples and update dac counter

            #256 FOR                            \ 256 samples per 512 byte sector

              SD@ SD@                                         \ Get two bytes from the SD card

              $80 + B>W                         \ offset the signed value and combine into 16-bit value

              #16 SHL WAITCNT FRQ               \ left justify, synch, then update dac counter

            NEXT                                \ next sample

            SD@ SD@ 2DROP           \ drop the CRC

            BEGIN -1 RUNMOD -1 <> UNTIL         \ wait for SD card ready

          NEXT                                  \ next block

        THEN

        0 #12 CMD DROP                                        \ STOP multiple block read

        ;

END

{

( Demo - play a file located at the address for n blocks @ 11.025kHz on P20 )

$5.4000 #6332 #11,025 #P20 PLAY

( If we are always using the same pin and sample frequency we could reduce the call parameters with this: )

: PLAY20 ( addr blocks -- )     #11,025 #P20 PLAY ;

( If that was the POPCORN wave file then we can create a definition for quick play )

: POPCORN                       $5.4000 #6332 PLAY20 ;

( Here's a version that factors out some code into reusable sections, skips any checking, and consumes just 70 code bytes )

: GetSample ( -- sample )      

      SD@ SD@ $80 + B>W

      ;

: WhenReady

      BEGIN -1 RUNMOD -1 <> UNTIL

      ;

: PLAY ( addr blocks rate pin -- )

      A DUTY APIN                              \ audio dac using counter A in duty mode to pin

      ROT #18 CMD DROP                         \ Issue a multiple block read command with addr

      WhenReady                                \ when SD card is ready

      CLKFREQ SWAP / DELTA                     \ set sample period from rate

      FOR                                      \ for multiple blocks - read samples and update dac counter

        #256 FOR                               \ 256 samples per 512 byte sector

          GetSample                            \ Get a 16-bit biased sample from the SD card  

          #16 SHL WAITCNT FRQ                  \ left justify, synch, then update dac counter

          NEXT                                   \ next sample

          GetSample DROP                         \ drop the CRC (treat as a sample)

        WhenReady                              \ wait for SD card ready

      NEXT                                     \ next block

      0 #12 CMD DROP                           \ STOP multiple block read

      ;

}