How to mix wav data
prolow
Posts: 3
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.
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
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.
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: 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