• Home
  • Reviews
  • Articles
  • News
  • Tools
  • GamingHeaven
  • Forums
  • Network
 

Go Back   DriverHeaven.net > Forums > Hardware and Related Topics > kX Project Audio Driver Support Forum > Effects and the DSP

Notices

Reply
 
LinkBack Thread Tools
Old Jan 17, 2006, 04:40 AM   #1
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

New! 4ch delay plug-in... Delay 4D!

Its a SURROUND panning delay.

Ok - so its not all mine - I TOTALLY RIPPED this off of Max M -

I just added 2 more delay taps and 2 more outputs.

(Im MUCH more efficient 'hacking' than writing.. hehe - sorry max, I hope you dont mind :S )

Anyway, I commented out the changes I made..
Hell, I'm VERY suprised this works lol
Not really sure why it works, but I seen a pattern and just replicated the logical parts.. ??

Or? - did I screw it up...

Code:
 ; Generated by kX DSP Editor - microcode dump
name "Delay 4D";
copyright "(c) Mark Davis 2006 - Based on work by: (c)Max Mikhailov, 2003-2005";
; NOTE The present DSP microcode dump is protected by the 
; license agreement bundled with the appropriate software 
; package containing this microcode,
; regardless the particular copyright notice is present in the dump.

comment "mono->4 ch panning delay";
	guid "e7e71636-0fb8-4a02-98d3-af3940cf36dc";
	; -- generated GUID


; itramsize 0
xtramsize 64002
; Registers
	input in1, in2;
	output out1, out2, out3, out4;
	control dry=0x0, wet=0x7fffffff, feedback=0x547ae147;
	control time=0x7fffffff, panning=0x2a3d70a3;
	static maxdlysize=0x3e80000;
	temp q, z;
; External TRAM delay line (64002 samples; ~1.333375 sec)
	xdelay write d1 at 0x0;
	xdelay read d1r at 0x3e80; added/ changed 1st tap point
	xdelay read d2r at 0x7d00; original 1st tap point
	xdelay read d3r at 0xbb80; added / 3rd/intermediate tap point
	xdelay read d4r at 0xfa00; original 2nd tap point.

; Code
	 ;macsn 	 z,  0x0,  d2r,  feedback;
	 macsn 	  z, 0x0, d4r, feedback;  changed this to get 4th instead of 2nd point
	 
	 ;interp 	 q,  d1r,  panning,  z;
	 interp 	 q,  d3r,  panning,  z; 
	 macs 	 0x0,  0x0,  q,  wet;
	 macs 	 out1,  accum,  in1,  dry;
	 
	 ;interp 	 q,  z,  panning,  d1r;
	 interp 	 q,  z,  panning,  d3r;
	 macs 	 0x0,  0x0,  q,  wet;
	 macs 	 out2,  accum,  in2,  dry;
	 
	 ;interp 	 q,  z,  panning,  d1r;
	 interp 	 q,  z,  panning,  d2r;
	 macs 	 0x0,  0x0,  q,  wet;
	 macs 	 out3,  accum,  in1,  dry;	 
	 
		  ;interp 	 q,  z,  panning,  d1r;
	 interp 	 q,  z,  panning,  d1r;
	 macs 	 0x0,  0x0,  q,  wet;
	 macs 	 out4,  accum,  in2,  dry;
	 
	 
	 interp 	 0x0,  in1,  0x40000000,  in2;
	 macs 	 d1,  accum,  z,  feedback;
	 macs 	 &d4r,  &d3r,  maxdlysize,  time; added 4th taps 'difusion filter '??    
	 macs 	 &d3r,  &d2r,  maxdlysize,  time; added 3rd taps 'diffusion filter' ??
	 macs 	 &d2r,  &d1r,  maxdlysize,  time; existing
	 macs 	 &d1r,  &d1,  maxdlysize,  time;

end

Last edited by Maddogg6; Jan 17, 2006 at 01:07 PM. Reason: fixed typo in code, added a couple comments
Maddogg6 is offline   Reply With Quote
Old Jan 17, 2006, 07:34 AM   #2
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

After just a quick lookover:

I am not sure why you changed the 1st instruction from a MACSN to a MACS...

You cut the original delays in half, but did not change the maxdlysize to reflect that, so your read points are going to be all wrong. You should either double the size of the tram (and set your initial read points to match), or adjust the maxdlysize to match the new delay sizes.
maxdlysize = delay_size * 0x800 (32000 * 0x800 = 0x3E80000 for the orginal delays)

You do not have seperate controls for both stereo channels, so I would guess that the 2 stereo channels will be the same, in which case you could have just copied the front to the back. You might try adding a seperate control for the rear panning/balance, and/or a front/rear fader control (and I am not sure you need the extra taps in the first place, without having a seperate delay time control for the rear channels).

Last edited by Russ; Jan 17, 2006 at 08:13 AM.
Russ is offline   Reply With Quote
Old Jan 17, 2006, 12:52 PM   #3
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

Quote:
Originally Posted by Russ
After just a quick lookover:

I am not sure why you changed the 1st instruction from a MACSN to a MACS...

You cut the original delays in half, but did not change the maxdlysize to reflect that, so your read points are going to be all wrong. You should either double the size of the tram (and set your initial read points to match), or adjust the maxdlysize to match the new delay sizes.
maxdlysize = delay_size * 0x800 (32000 * 0x800 = 0x3E80000 for the orginal delays)

You do not have seperate controls for both stereo channels, so I would guess that the 2 stereo channels will be the same, in which case you could have just copied the front to the back. You might try adding a seperate control for the rear panning/balance, and/or a front/rear fader control (and I am not sure you need the extra taps in the first place, without having a seperate delay time control for the rear channels).
The macsn -> macs - was a typo - hehe, it still 'functioned' as surround delay.
Didnt this mistake 'just invert the 4th tap'?

Ok I admit , Im still completely lost...

But,
Id think... if I kept the xtram size and re-used same tap points, but add intermediate tap points (0x3e80 & 0xbb80) eliminated the pointer problems you described.. ??
Whats the 'effect' of the pointer error, I mean, dane doent give error as is - would the delays be inconsistant if pointers were off... ? Cuz so far its sounds consistant.

Ill look at more delays and see what I can learn... LOL

Im just happy it sounded like surround delay.. hehe
Maddogg6 is offline   Reply With Quote
Old Jan 17, 2006, 01:48 PM   #4
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

Well basically you made a delay, with 4 read pointers (every 16000 samples), but the code to dynamically change the read pointers is using a size of 32000 samples.

Now lets say that you set the TIME to full.
Your 1st read pointer will be a 32000 (32000 past the write pointer (0)).
Your 2nd read pointer will be a 64000 (32000 past the 1st read pointer).
Now your 3rd and 4th read pointer will be beyond the size of the TRAM.

Basically any time setting > 50% will have problems.

This is not the type of error Dane would catch because it is happening dynamically.

BTW: With the actual code you are using, it may be even worse, because the read pointers are changed in reverse order.

Again with a TIME setting of full.
Your 4th and 3rd read pointers are again beyond the size of the TRAM.
Your 2nd read pointer is 48000 (32000 past the initial 1st read pointer (16000)).
Your 1st read pointer is at 32000 (32000 past the write pointer (0).
That makes the delay times different for the 1st and 2nd read pointer. (the first one is 32000 samples, but the second is only 16000 samples later).

Last edited by Russ; Jan 17, 2006 at 02:08 PM.
Russ is offline   Reply With Quote
Old Jan 17, 2006, 02:15 PM   #5
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

Ok - I see the panning control doesnt act as expected...

So I set that as static and removed the control

It does sound cool when set to 50%

Last edited by Maddogg6; Jan 17, 2006 at 02:25 PM.
Maddogg6 is offline   Reply With Quote
Old Jan 17, 2006, 02:49 PM   #6
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

Max's code isn't always the best to try and learn from for people just starting out. He knows the instructions very well, and is very efficient with his coding. This can make it difficult to figure out exactly what the code is doing.
Russ is offline   Reply With Quote
Old Jan 17, 2006, 03:49 PM   #7
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

ahh - so

Optimized code = confusion...

hmmm this notion sux... lol
Maddogg6 is offline   Reply With Quote
Old Jan 17, 2006, 04:46 PM   #8
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

Well it is not just the the optimized code, I mean you could understand exactly what some code is doing and still not understand why it does what it does.

In any case, what did you want it to do?
i.e.
Did you want the front to be a copy of the back?
Did you want it to ping-pong around the room?
Russ is offline   Reply With Quote
Old Jan 17, 2006, 06:04 PM   #9
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

Well, I didnt have any real expectations of the out come...
I read 'Jump in and do stuff' is best way to learn - so, I find the highest diving board, on the windiest day, at the smallest pool I can find, on the most crowded day.... and just dive in...

But thats just my M.O. -lol

I guess... I did assume that the pattern would be 'Z' shaped - based on how the originals behavior was - its how it sounds too -

But - the rears sound first - then the fronts more delayed.

Sounds cool with midi solo instruments.

So yes, I understand - the algo disctates the 'pattern' of delays...

I just figured -'Hey, theres no surround delays'

And started toying around ... its kinda fun and frustrating at the same time -

Just was playing around to get the 'rears' in on all the action.
Maddogg6 is offline   Reply With Quote
Old Jan 17, 2006, 07:17 PM   #10
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

Thats ok, you learned something, right?

I did some of the same things when I was figuring this stuff out.
i.e.
I figured out how to modulate the delay lines by reading the ask10k1 manual, and looking at code for the 'Delay A' plugin IIRC. If you haven't looked at the as10k1 manual as of yet, you should, as it does contain some information that is not available elsewhere.

Last edited by Russ; Jan 17, 2006 at 07:24 PM.
Russ is offline   Reply With Quote
Old Jan 18, 2006, 07:38 AM   #11
DriverHeaven Lover
 
radiocolonel.it's Avatar
 
Join Date: Jan 2005
Location: Italy
Posts: 192
radiocolonel.it is on a distinguished road

Quote:
Originally Posted by Russ
Max's code isn't always the best to try and learn from for people just starting out. He knows the instructions very well, and is very efficient with his coding. This can make it difficult to figure out exactly what the code is doing.
That's right Max is kinda "artist" of dane, and as he says it depends on knowledge and a bit of magician...

Last edited by radiocolonel.it; Jan 18, 2006 at 07:45 AM.
radiocolonel.it is offline   Reply With Quote
Old Jan 18, 2006, 11:55 AM   #12
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

@Russ:
Yeah.. Im learning alot - that formula>dane thing that tril explained was like THE most enlightening thing thus far tho. I think it was my first brickwall - understanding how formulas translate into dane.

Im still looking at the examples and trying to understand how delays work.

I did print out the 10K1 manual - I also got the fx8010 one too.
They start making more sense, going back to them now...


@Radiocolonel:
Its true - Max seems like quite the magician .. hehe - definitly something to aspire too.

Also - Ive been using your stereo widener for my 'TV watching' dsp config.
Er - I think its yours anyway - soo many plugins its hard to keep track - [*looking at plugin*] no credits but name 'ColHQ WIDENER' makes me think its yours hehe..

anyway - I like it... But was wondering what 'formula' you used - is it an 'interleaving comb filter' ?
Maddogg6 is offline   Reply With Quote
Old Jan 18, 2006, 01:21 PM   #13
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

Delay lines are actually pretty easy (once you know the specifics), but you should start with simple delay lines (i.e. a simple delay or a simple echo, without the extras).

The only real trick (which is not in the guide, but is explained in the as10k1 manual), is updating the read/write pointers to change the delay time on the fly (from a slider or whatever).

Delay time (number of seconds) = (size of delay line (in samples) -1 ) / 48000).
The TRAM starting index is at 0, so the read pointer would always be 1 less than the delay size.
i.e.
A 1 sec delay line, would have a size of 48001 samples, and the read pointer (the write pointer is at 0) would be at 48000.

For 2 delay lines (for stereo or whatever) of 1 sec each, you would have a size of 96002. The first read and write pointer would be the same as above. The second write pointer would be at 48001, and the second read pointer would be at 96001.

The '&' symbol you see in Max's code means "address of", and that is what you use to change the address of the read pointer.
i.e.
macs &d1r, &d1, maxdlysize, time;

That means: the address of the first read pointer will be changed to: (the address of the write pointer) + (( the size of the delay line * 0x800) * (percentage of the full delay))

The 0x800 thing is explained in the as10k1 manual.
For both examples above, the delay lines are 48000 samples, so the maxdlysize would equal 0x5DC0000 (48000 * 0x800).

If you search the forum the are some examples of simple delays that you could use for reference.

Last edited by Russ; Jan 18, 2006 at 03:02 PM.
Russ is offline   Reply With Quote
Old Jan 18, 2006, 03:16 PM   #14
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

Ok - I'll need to time to ingest this... :S


BUT the '&d1l' - so this is like 'indirect addressing' type of thing in other assemblers then?

in other words

I have a variable; its Called 'APPLES'; Its contents is '27'; This is stored in 0x0XXXXX

So using the '&APPLES = 0x0YYYYYY' - Im changing the LOCATION this variable is stored in. Not the CONTENTS of the variable - APPLES still = 27.

right? - if so it makes alot of sense..
Maddogg6 is offline   Reply With Quote
Old Jan 18, 2006, 03:38 PM   #15
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

You are close, but not exactly right.
It is indirect addressing, but it is more like this:
You have an array of apples each with its own value and own address (in contiguous memory).
Now lets say we have an APPLE variable whose address is the address of one of the apples in the APPLES array, whose value is 27.
Using '&APPLE = 0x0YYYYYY' would change the address of the APPLE variable, such that it points to a different apple in the APPLES array. It does not change the value of the first apple, but rather allows us to use the same variable to get the value of a different apple in the array.

Does that make sense?

<edit>
BTW: They key here is that it is contiguous memory. This means that each apple is stored one after the other in memory, so you can change the pointer/address using math. i.e. You can move the pointer to the next apple in the array by adding (1 * the size of an APPLE) to the current address, or by adding (10 * the size of an APPLE) you could move ahead 10 apples, or whatever. If starting from the beginning of the array, you can move to any particulair apple you want, based on its position in the array, or by using the size of the array, you can pick any apple based on some percentage of that size, etc. (i.e. from a slider setting or whatever).
</edit>

Last edited by Russ; Jan 18, 2006 at 05:52 PM.
Russ is offline   Reply With Quote
Old Jan 29, 2006, 02:34 PM   #16
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

Dang - for some reason this forum makes it easy to miss posts - while still showing ones that I HAVE read... Maybe it how FF processes cookies??

Sorry Russ.

Yes it does sorta make sense, IIRC thats the nature of indirect addressing - weather we read or write to it also makes the difference if APPLES contents are change.

For instance:
if APPLE contains 27 and is stored in 0x01
and ORANGE contains 99 and is stored in 0x02

We execute the following in DANE:

&APPLE = 0x02

The result I would expect would be:

APPLE = 99

And the Mem dump:
0x01 = 27
ox02 = 99

So the memory hasnt changed EXCEPT the pointer to APPLES variable contents location.
Which should ALSO equal the pointer for ORANGES variable contents location.

we ONLY change what apple contains (now 99) - but mem location 0x01 STILL equal 27 - is this correct?

- I understand the 'ADDRESS' is located in a 'RING' which makes it contigious.
I understand Im not offestting (the +1) like I should be.

Im still gonna need to digest this tho. - I moved on to a new idea - I know, Im ALL over the place. - but I wanted to 'lower' the difficulty for me in a new direction.

I'll come back to more unique delays when I get a better grasp on all this.
Maddogg6 is offline   Reply With Quote
Old Jan 29, 2006, 09:19 PM   #17
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

Lets not confuse TRAM usage in Dane, with pointers in general. I was really only responding to your example, but this is not really stuff you need to know to use the TRAM or Dane.

It (pointers in general) is a little more complicated than that. You should not really be mixing apples and oranges here, because we do not know the size of these objects, and the size makes a difference when you are talking about array indices (and objects in memory), etc.

For TRAM, all we are really talking about is an 'X' number of delayed samples from some starting point (the write pointer or another read pointer, etc), or, some percentage of the size of the delay line. All you really need to know for this is the magic number 0x800.

i.e.
To change the read pointer to some specific number of samples beyond some starting point (the write pointer here, but it could be another read pointer, or whatever):
READ_PTR_ADDR = WRITE_PTR_ADDR + (NUMBER_OF_SAMPLES * 0x800)

Or to change the read pointer to some percentage of the delay size (i.e. based on a slider value):
READ_PTR_ADDR = WRITE_PTR_ADDR + ((DELAY_SIZE * 0x800) * PERCENTAGE)
Russ is offline   Reply With Quote
Old Jan 29, 2006, 11:35 PM   #18
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

hehe - this is making my brain hurt - I seem to be slow at grasping all this.

Ill continue to try - cuz I DO want to make some new delay algos. I DO want to understand it and NOT 'accidentally' stumble on something. lol
Maddogg6 is offline   Reply With Quote
Old Jan 30, 2006, 01:05 AM   #19
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

I think maybe you are just over thinking it. Forget about the addressing and just think of what the delay line is. You put data in at some point (the write pointer), and every sample cycle, that data moves forward to the next position, and you read the data back out somewhere else.

i.e.
You put the data in at position 0, and you have a read pointer at 5.
After one cycle, that data is at position 1.
After two cycles, that data is at position 2.
After three cycles, that data is at position 3.
After four cycles, that data is at position 4.
After five cycles, that data is at position 5, where you read pointer is, so what you are reading is a sample from 5 cycles ago, thus it is delayed 5 cycles.
If you fed a sample into position 0, every cycle, then you will get those same samples back out 5 cycles later, so they are all delayed by 5 samples. Now the samples are not removed from the delay line, they keep moving until they reach the end, so if you had another read pointer further down the line, then you would get the same samples again but a more delayed version of it.

If you wanted to change the read pointer at run time, to creater a longer or shorter delay, then you use the math from my previous post to do it.
i.e. To move the first read pointer to position 10:
[ READ_PTR_ADDR = WRITE_PTR_ADDR + (10 * 0x800) ] (10 after the write pointer. So, the 0x800 is irrelevant for your calculation, it is used simply to calculate the address).

Now if you were using a slider (ignoring the 0x800 thing for the moment):
Say your delay line is 100 samples (MAXDELAYSIZE = 100).
Say your slider is at 50%, so you want the delay time to be half of the total time (MAXDELAYSIZE * 50%):
[ 100 * .50 = 50 ], which is half the delay line. Now, if you had the wrong size for the total delay, then you would get the wrong answer.

Now lets double the size of the delay line, and add a second read pointer, but keep the first read pointer within the same range as it was previously (i.e. 50% still equals 50 samples). We will move the first read pointer from the write position, and we will move the second read pointer from the first read position (so the delay time of the 2nd read ptr will be double that of the first).
Total delay is 200, but we want each read pointer to have a max delay of 100 (to keep the same range as before), so MAXDELAYSIZE = 100.
[ 1st_READ_PTR = WRITE_PTR + (100 * .50) ] or 1st_READ_PTR = 50 (0 + 50)
[ 2nd_READ_PTR = 1ST_READ_PTR + (100 * .50) ] or 2nd_READ_PTR = 100 (50+50)

Now if we decided to just add a couple more read points in between, like in your example code, without changing the MAXDELAYSIZE:
[ 1st_READ_PTR = WRITE_PTR + (100 * .50) ] or 1st_READ_PTR = 50 (0 + 50)
[ 2nd_READ_PTR = 1ST_READ_PTR + (100 * .50) ] or 2nd_READ_PTR = 100 (50 + 50)
[ 3rd_READ_PTR = 2nd_READ_PTR + (100 * .50) ] or 3rd_READ_PTR = 150 (100 + 50)
[ 4th_READ_PTR = 3rd_READ_PTR + (100 * .50) ] or 4th_READ_PTR = 200 (150 + 50)

From the above, you can see that with the slider at only 50%, the 4th read pointer is at exactly the size of the total delay line, so anything above 50% will result in a values beyond the size of the delay line. The math is pretty straight forward there, and is what you would use to design your delays. The 0x800 is only for converting those numbers to the correct addresses, so in your code you would mutiply the MAXDELAYSIZE by 0x800, but you do not have to think about that when you are designing your delay lines, you should only be concerned with how much delay you want, and if your delay line is the correct size for the max delay you want (or if you split it up into multiple parts, that the max delay size of each part, when added together does not exceed the size of the complete delay line).

BTW: If you add additional write pointers, then you are basically splitting the delay line into multiple delay lines. The end of the first delay line would be the position right before the second write pointer, etc.

Last edited by Russ; Jan 30, 2006 at 01:33 AM. Reason: typo
Russ is offline   Reply With Quote
Old Jan 30, 2006, 06:12 AM   #20
DriverHeaven Lover
 
radiocolonel.it's Avatar
 
Join Date: Jan 2005
Location: Italy
Posts: 192
radiocolonel.it is on a distinguished road

Quote:
Originally Posted by Maddogg6


@Radiocolonel:
Its true - Max seems like quite the magician .. hehe - definitly something to aspire too.

Also - Ive been using your stereo widener for my 'TV watching' dsp config.
Er - I think its yours anyway - soo many plugins its hard to keep track - [*looking at plugin*] no credits but name 'ColHQ WIDENER' makes me think its yours hehe..

anyway - I like it... But was wondering what 'formula' you used - is it an 'interleaving comb filter' ?
Yeah the widener is an idea of mine, max helped me to optimize the code and teaching me how to reuse some registers. Yeah the name ColHq would stand for Colonel High Quality...

the formula i used is simple
i subtract from the left channel the right one... what comes out from this operation i add to the left channel.... i do the same for the right! Simple, very simple but effective! U make me happy saying that u use that plugin! I don't know if u so my others anyway here they are (dane.zip):

http://xoomer.virgilio.it/ars_acustica/kx/


they are simple, so good to learn, some of them don't have optimized code... so it's even easier. I hope i helped you a little bit.
radiocolonel.it is offline   Reply With Quote
Old Jan 30, 2006, 01:50 PM   #21
Tail Razer
 
Maddogg6's Avatar
 
Join Date: Jun 2005
Location: Bernyurass, AZ - USA
Posts: 3,721
Maddogg6 will become famous soon enough

First off - you are NOW called 'Saint Russ' - the PATIENT saint.
Thank you for putting up with my thickness...

Quote:
Originally Posted by Russ
I think maybe you are just over thinking it. Forget about the addressing and just think of what the delay line is. You put data in at some point (the write pointer), and every sample cycle, that data moves forward to the next position, and you read the data back out somewhere else.
i.e.
You put the data in at position 0, and you have a read pointer at 5.
After one cycle, that data is at position 1.
After two cycles, that data is at position 2.
After three cycles, that data is at position 3.
After four cycles, that data is at position 4.
After five cycles, that data is at position 5, where you read pointer is, so what you are reading is a sample from 5 cycles ago, thus it is delayed 5 cycles.
If you fed a sample into position 0, every cycle, then you will get those same samples back out 5 cycles later, so they are all delayed by 5 samples. Now the samples are not removed from the delay line, they keep moving until they reach the end, so if you had another read pointer further down the line, then you would get the same samples again but a more delayed version of it.[/quote]

The above makes perfect sense to me -

(note: questions are numbered for your answering convenience)

1) Additional read pointers would give us more 'taps' also - correct?
Quote:
Originally Posted by Russ
If you wanted to change the read pointer at run time, to creater a longer or shorter delay, then you use the math from my previous post to do it.
i.e. To move the first read pointer to position 10:
[ READ_PTR_ADDR = WRITE_PTR_ADDR + (10 * 0x800) ] (10 after the write pointer. So, the 0x800 is irrelevant for your calculation, it is used simply to calculate the address).

Now if you were using a slider (ignoring the 0x800 thing for the moment):
Say your delay line is 100 samples (MAXDELAYSIZE = 100).
Say your slider is at 50%, so you want the delay time to be half of the total time (MAXDELAYSIZE * 50%):
[ 100 * .50 = 50 ], which is half the delay line. Now, if you had the wrong size for the total delay, then you would get the wrong answer.

Now lets double the size of the delay line, and add a second read pointer, but keep the first read pointer within the same range as it was previously (i.e. 50% still equals 50 samples). We will move the first read pointer from the write position, and we will move the second read pointer from the first read position (so the delay time of the 2nd read ptr will be double that of the first).
Total delay is 200, but we want each read pointer to have a max delay of 100 (to keep the same range as before), so MAXDELAYSIZE = 100.
[ 1st_READ_PTR = WRITE_PTR + (100 * .50) ] or 1st_READ_PTR = 50 (0 + 50)
[ 2nd_READ_PTR = 1ST_READ_PTR + (100 * .50) ] or 2nd_READ_PTR = 100 (50+50)

Now if we decided to just add a couple more read points in between, like in your example code, without changing the MAXDELAYSIZE:
[ 1st_READ_PTR = WRITE_PTR + (100 * .50) ] or 1st_READ_PTR = 50 (0 + 50)
[ 2nd_READ_PTR = 1ST_READ_PTR + (100 * .50) ] or 2nd_READ_PTR = 100 (50 + 50)
[ 3rd_READ_PTR = 2nd_READ_PTR + (100 * .50) ] or 3rd_READ_PTR = 150 (100 + 50)
[ 4th_READ_PTR = 3rd_READ_PTR + (100 * .50) ] or 4th_READ_PTR = 200 (150 + 50)

From the above, you can see that with the slider at only 50%, the 4th read pointer is at exactly the size of the total delay line, so anything above 50% will result in a values beyond the size of the delay line. The math is pretty straight forward there, and is what you would use to design your delays. The 0x800 is only for converting those numbers to the correct addresses, so in your code you would mutiply the MAXDELAYSIZE by 0x800, but you do not have to think about that when you are designing your delay lines, you should only be concerned with how much delay you want, and if your delay line is the correct size for the max delay you want (or if you split it up into multiple parts, that the max delay size of each part, when added together does not exceed the size of the complete delay line).
OK - What hapens when 'anything above 50% will result in a values beyond the size of the delay line.' - these samples are lost because they would be re-written to/over - correct?

Quote:
Originally Posted by Russ

BTW: If you add additional write pointers, then you are basically splitting the delay line into multiple delay lines. The end of the first delay line would be the position right before the second write pointer, etc.
Ok - this is how we can get stereo and multiple taps
ie.

2) for stereo we'd need at least; 2 inputs, 2 outputs, 2 write pointers and 2 read pointers - correct?

3) for multiple taps we simply add more read pointers at various addresses with in the maxtramsize range - correct?

4) to have feed back - we need to mix final output with a read points contents and re-write that result to some (maybe same as said read point) tram location - correct?

5) and NO need to CHANGE pointers (at run time) UNTIL we want to adjust the delay time (via a slider for instance) or have some dynamic tap points - correct?

Thanks again Russ. - Er, Saint Russ.http://www.driverheaven.net/images/s...big%20grin.gif
Maddogg6 is offline   Reply With Quote
Old Jan 30, 2006, 02:07 PM   #22
DriverHeaven Extreme Member
 
Join Date: Jan 2005
Posts: 4,104
Russ has a spectacular aura aboutRuss has a spectacular aura aboutRuss has a spectacular aura about

hehe

1) Yes, and, I am not really sure what happens when you write beyond the size of the TRAM. Under normal circumstances it would be corrupting some memory somewhere else (very bad), but I am not sure what it does here (and in this case, you are actually reading, not writing anything, so I guess the worst thing that would happen is you would get data that is not audio data).

2) Yes, for independant channels.

3) Yes.

4) Yes, but you would write the feedback to a write location (you cannot write to anywhere other than a write location).

5) Yes.