Audio Delay
geokonst
Posts: 48
Dear all,
I would like your opinion on something. I am trying to make a prop audio delay. I came up with the following
Which is practically a 11bit 39steps shift register. My question is: Is there a better way to do this? I am not confident about the timing of the shifting for i loop. I believe it works ok but I am not that experienced.
Another thing; Is the delay 1ms? The sampling frequency is 39Khz for 11bits. Is my program oversampling the adc object?
Finally, I get a DC offset of more than 1.5V with the mic circuit and approx 0,8 with the proposed ADC circuit. Anyone know why is that? Would a decoupling cap fix this or is it a softADC thing?
Thank you in advance.
I would like your opinion on something. I am trying to make a prop audio delay. I came up with the following
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 OBJ adc : "Dual_ADC" vp : "ViewportConduit_20" VAR long buffer [noparse][[/noparse]39] long out PUB start | inc 'INITIALISATION adc.start (8,24,9,26,11) 'SHIFT REGISTER repeat buffer:=adc.read1 repeat inc from 1 to 38 buffer[noparse][[/noparse]inc+1] := buffer[noparse][[/noparse]inc] out:=buffer[noparse][[/noparse]39]
Which is practically a 11bit 39steps shift register. My question is: Is there a better way to do this? I am not confident about the timing of the shifting for i loop. I believe it works ok but I am not that experienced.
Another thing; Is the delay 1ms? The sampling frequency is 39Khz for 11bits. Is my program oversampling the adc object?
Finally, I get a DC offset of more than 1.5V with the mic circuit and approx 0,8 with the proposed ADC circuit. Anyone know why is that? Would a decoupling cap fix this or is it a softADC thing?
Thank you in advance.
Comments
Yes, a circular buffer. Thus you avoid the waste of time shifting the buffer around.
A circular buffer has two pointers (indizes) into it. One for writing and one for reading. When the pointer reached the end, he simply wraps around. By increasing the difference between write and read-pointer, you can adjust the delay.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
You'd have to time it, but most likely not. You are buffering through a 39 stage delay, so the delay is 39 x sample rate. If you are sampling once every 25uS that's around 1ms delay.
The sampling frequency is 39Khz for 11bits.
To get 39kHz you need to take a sample every 25us. Spin is almost certainly too slow to do this which is why other programs you have looked at have been written in Assembler.
The REPEAT loop as given will take around 1.1 ms thus slowing the acquisition to 900 Samples = 450 Hz
The usual implementation of a queue by a ring buffer as explained by Nick will run in about 40 µs, adding the Dual- ADC access and some output for a DAC adding the same time again, takes 80 µs = 12000 samples = 6 kHz Thats quite telephone or AM radio - not so bad I should say.
deSilva: 1.1 ms!!! sounds awfull. I checked with viewport and the waveform looked ok. Would the sampling frequency be higher than 12kHz using assembly?
Beau has posted a very short "echo program" some time ago using exactly your strategy.
At 39 kHz = 25µs you can run 500 machine instructions, that will be enough for some basic signal processing
But then, what are the remaining 7 cogs for?
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
to give you an insight:
I want to do dual adc but with one channel delayed at any time. This is of course part of the convolution I am trying to do for soooo long [noparse]:)[/noparse]. Beau should make his code into an object (with bits and delay time as inputs) in obex as I beleive it's extremely useful (more than mic2headphones).
This means samples could be missed since the loop is slower then one sample duration.
It'll work, but your output sampling rate is different then what is coming in. This also generates aliasing niose at the differential Nyquist frequency.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Share the knowledge: propeller.wikispaces.com
Lets make some music: www.andrewarsenault.com/hss
THINK COGS!
If the ADC and DAC aren't hooked to the same I2C-bus, you could do the following:
The ADC-cog loops through
The DAC-cog:
Then you have a third COG that sets the signals for the ADC-cog and the DAC-cog, does all the necessary delays and is writing to and reading from his ring buffer getting the value through TheGlobalADCValue and setting it through TheGlobalDACValue
HTH,
Nick, voting for more cogs!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
Post Edited (Nick Mueller) : 1/4/2008 8:00:10 PM GMT
Dual-ADC is the frist COG you describe (really nice code from Raymond Allen!)
And - granted - your second COG is still missing; it only says
out:=buffer[noparse][[/noparse] 39 ]
at the moment..
after the delay it will be something like
out:=buffer[noparse][[/noparse]39] + adc.read2 'Where the second microphone is connected
which for various delays will give a convolution (remember that) of two signals.
Since deSilva's first answer I've been trying to modify the dualADC to do delay using Beau's code with (offcourse) no results. At this point I would like to thank you all for your answers so far and for Raymond's excellent and easy to use code.
something like this, always FIFO:
repeat while delay_on
__index:=(index+1)//buffer_size
__digital_out:=BYTE[noparse][[/noparse]buffer+index]
__BYTE[noparse][[/noparse]buffer+index]:=digital_in
If you do use two indexes it gives effects such as changing voice pitch if they add more than one.
If one of two indexes counts backwards it sounds like playing backwards or evil voice of doom.
If you try to do delay with just props hub or cog ram, you wouldnt be able to instantaneously change the RANGE of delay for more than the amount of sample time that the registers took to fully load up in the first place, without losing samples.· Most tape delays are just·realtime static delay,·but if you wanted to innovate, or do extreme pitch shifting,·SD would be the way to go.· Or wait for prop·II. whatever.
Post Edited (Sleazy - G) : 1/5/2008 10:27:05 AM GMT
SD cards can be written @ 100kBy/s with is fast enough at the first glance However you need alternating reading AND writing for a delay algorithm with caching, which will make the algorithm more complex, and double the needed bandwidth!
This looks like an application perfect for external FRAM, accessed via SPI.
Exactly?
What he does is a blocking read.
My scetch is following more the principles of multi-threaded programming.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
The main issue with SPIN is the missing transformation throughput ("transformation" = "copy", just a special case ) Even ringbuffer has too much overhead for 40k Byte/sec.
Unfortunately I can't wait for PropII. I have to prove within 2 months that a 10quid chip can do things others use fpgas for.
Post Edited (geokonst) : 1/5/2008 12:40:18 PM GMT
Sorry, I was just eyeballing because I didn't have the code. :-/
Parallax-search doesn't find "Dual_ADC", Google search finds the Dual_ADC.spin, but not this thread.
> Even ringbuffer has too much overhead for 40k Byte/sec.
I get 16.5kHz out of it, with a simulated call to the ADC and an "out:= RingBuffer[noparse][[/noparse] someindex ]" Plus it is running in a counted repeat that eats some ticks too.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
Thanks
You also have to accept that it may not, or not in the way you are currently trying to do it. My recommendations would be -
1) Get to grips with assembly language (PASM) programming. Sampling every 25uS (40kHz) should be achievable.
2) Create a simple ADC to DAC 'copy' program which replicates output from input. Get that working as required.
3) Add the delay functionality. You only need to hold 40 samples for a 1mS delay which can be held in Cog memory or Hub memory.
Personally, I think (3) is the easiest part, especially once you've completed (1) and (2). I have no idea how complicated implementing ADC and DAC will be, but it appears there is already an ADC 'reference design' which should make that easier.
Learning to use PASM is an unknown quantity, but the sooner you start, the sooner you'll become experienced. A 25uS loop is quite a long period for a 20 MIPS processor so you don't have the difficult task of a project which requires extensively optimised coding from the start. Even for an experienced assembly programmer PASM's necessary use of self-modifying code is an initial hurdle to get over. I would say it has taken me between one and two months to become what I'd consider proficient in PASM. I expect the learning curve would be shorter if entirely focused on that or with a good aptitude for the Propeller architecture.
I believe what you are trying to do should be achievable within two months.
But this is of no relevance. It should just show again the limits of SPIN in this specific area.
SPIN can be used for some (not all) feasibility studies @ 10kHz
Untested, but here's one version ...
An equivalent, also untested, in PASM ...
No, I had that in the code too.
The "trick" to get it that fast is to make the circular buffer sized to powers of 2 and not to make a MOD for the index, but to mask the index after the increment
For geokonst:
It doesn't make a difference wether you use long, word or byte.
HTH,
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
---
Edit:
@Hippy: Nice tricky use of COG space!
Post Edited (deSilva) : 1/6/2008 12:48:21 AM GMT
Nick-> Sorry I don't get it. Why a power of 2?
hippy -> It all started with great ambition. None has done sound source localization of continuous sounds based on anything smaller than an fpga before (at least I couldn’t find anything). When I saw the propeller I thought what an amazing chip! And so I started. Soon I got very disappointed when I got into the demands of such a system. I reached a point when I though it was not possible.Fpga would be so much easier. But then I saw stereospatialiser by Chip (which is almost what I want to do. imagine feeding the first adc to the stereospat and then adding the second adc to the left or right (depending on angle) output) and became optimistic again.
So yes in general I was prepared to accept it is not possible, but I now strongly believe it is.