Shop OBEX P1 Docs P2 Docs Learn Events
How to mix wav data — Parallax Forums

How to mix wav data

prolowprolow Posts: 3
edited 2014-07-04 17:43 in General Discussion
Hi all!
I'm working on a audio module for a pinball machine project.
It needs to simultaneously play music, commentary, and sounds effects. Mono 16bit 16khz is fine.
I'm working with a Propeller Quickstart and 3 x LC soft SD card modules.

I'm having trouble mixing the audio.
When I play more then one clip the output is extremely distorted.
'  essentially 3 x SPIN WAV Player Ver. 1a by Raymond Allen 2007
 
CON _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000       '80 MHz 
    buffSize = 256


VAR
  long runStack[64]
  long BuffA[buffSize]
  long BuffB[buffSize]
                     
  long play0Stack[64]
  word data0[buffSize]


  long play1Stack[64]  
  word data1[buffSize]
  
  long play2Stack[64]
  word data2[buffSize] 
    
OBJ
    term  : "Parallax Serial Terminal"
    SD[3] : "fsr"


PUB Main | r
  term.start(115_200)
  waitcnt(clkfreq * 4 + cnt)


  r := \sd[0].mount(0)
  r := \sd[1].mount(6)
  r := \sd[2].mount(12)
 
  longfill(@BuffA, 0, buffSize)
  longfill(@BuffB, 0, buffSize)


  COGNEW(Run(18),@runStack)
   
  CogNew(play0(string("test.wav")), @play0Stack)
  waitcnt(clkfreq + cnt)


  CogNew(play1(string("test.wav")), @play1Stack)
  waitcnt(clkfreq + cnt)
  
  'CogNew(play2(string("test.wav")), @play2Stack)
  'waitcnt(clkfreq + cnt)
         
PUB play0(fileName) | n, i, j
  i := \sd[0].popen(fileName, "r")
  i := \sd[0].pread(@data0, 44)
            
  'Keep filling buffers until end of file
  ' note:  using alternating buffers to keep data always at the ready...
  n := buffSize - 1
  j := buffSize * 2
  repeat while (j == buffsize * 2)  'repeat until end of file
    
    if (BuffA[n] == 0)
      j := sd[0].pread(@data0, buffSize * 2) 'add data to bufferA
      repeat i from 0 to n
        BuffA[i] += ($8000 + data0[i]) << 16              
                   
    if (BuffB[n] == 0)
      j := sd[0].pread(@data0, buffSize * 2) 'add data to bufferB
      repeat i from 0 to n
        BuffB[i] += ($8000 + data0[i]) << 16
    
  'must have reached the end of the file, so close it
  term.str(STRING("Closing: ", 13))  
  sd[0].pclose


      
PUB play1(fileName) | n, i, j
  i := \sd[1].popen(fileName, "r")
  i := \sd[1].pread(@data1, 44)

  n := buffSize - 1
  j := buffSize * 2
  repeat while (j == buffsize * 2)  'repeat until end of file
    
    if (BuffA[n] == 0)
      j := sd[1].pread(@data1, buffSize * 2) 'add data to bufferA
      repeat i from 0 to n
        BuffA[i] += ($8000 + data1[i]) << 16  
         
    if (BuffB[n] == 0)
      j := sd[1].pread(@data1, buffSize * 2) 'add data to bufferB
      repeat i from 0 to n
        BuffB[i] += ($8000 + data1[i]) << 16  


  term.str(STRING("Closing: ", 13))  
  sd[1].pclose


    
PUB Run(outPin)| i, nextCnt, j
  'Play the wav data using counter modules


  'Set pins to output mode
  DIRA[outPin]~~                              'Set Right Pin to output


  'Set up the counters
  CTRA := 110 << 26 + 0<<9 + outPin         'NCO/PWM Single-Ended APIN=Pin (BPIN=0 always 0)


  i := 0
  j := true
  NextCnt := cnt + 1005000


  'Play loop
  'This loop updates the counter with the new desired output level
  'Alternates between BuffA and BuffB so main program can keep buffers full
  repeat 
    repeat i from 0 to buffSize-1
      NextCnt += 5000   ' need this to be 5000 for 16KSPS   @ 80 MHz
      waitcnt(NextCnt)
      if (j)
        FRQA := BuffA[i]~
        FRQB := FRQA
      else
        FRQA := BuffB[i]~
        FRQB := FRQA  
    NOT j


Comments

  • KyeKye Posts: 2,200
    edited 2014-07-04 16:53
    Hi prolow,

    I'm not sure if a SPIN cog is going to give you enough performance. Maybe it can however. Usually, you want to do this in ASM. Does playing channel by itself work?

    Anyway, if you need multiple channels you just need to add the samples for each channel. You can't logically OR the I/O pins.

    ...

    The easiest way to get what you want without having to change a bunch of code is to just output the different audio channels on different pins and then use a summation-op-amp to add the signals together. http://www.electronics-tutorials.ws/opamp/opamp_4.html. It will impose a 180 degree phase shift, but this should not be an issue for you.
  • prolowprolow Posts: 3
    edited 2014-07-04 17:43
    Hey Kye, thanks for the reply.
    Yes, playing one sound works fine.
    I don't think performance has been an issue so far, even when reading and playing for all 3 sd cards at the same time, best I can tell the sample rate doesn't slow or hitch.

    I don't think I'm trying to switch pin in the code.
    I'm guessing the problem could arises here:
    BuffA[i] += ($8000 + data0[i]) << 16
    
    where I want the add this sounds data to the existing data in the buffer.
    BuffA is long
    data0 is word
    both are little endian
    the data is signed int
Sign In or Register to comment.