@nsigma
I wasn’t planning on using the Echo in a concurrent fashion. At first I had separate public poll() and add() methods, and this led to a reflex concern about concurrency. Since these have been combined into a single public entry point: tick(), as in a tick of a clock for a single sample, this isn’t a concern.
But I realize that the concurrency overhead eliminated (for example, by using a simple LinkedList as a queue) was not the only performance issue. By indexing into an array as you suggest, and overwriting instead of adding and deleting array elements, the dropouts have disappeared. Thank you!
As for the use of doubles, I have run into some confusion and trouble trying to keep track of when it is okay to use a double and when it is better to use a float. So, instead of solving this in a real way, I thought I’d try just making everything a double and leave the optimization to floats to a later time. I will reconsider this.
Maybe this guideline will work (floats vs doubles):
audio data - float (that is what is in the WaveTable now, I’m just returning the float into a double currently)
index into wave table audio data (e.g., for interpolation locations for pitch variation) - double
math ops, such as multiplication by a volume value between 0 and 1 - float is OK? that is where I started using doubles.
@ShannonSmith
Good checklist! Thank you.
(1) - “Don’t use any synchronization at all”
I may have one exception to this. There was no need of any synchronization in my implementation of the tone generator. But I think there is a possible concurrency danger in the conversion of real-time mouse data to pitch and volume values. It is impossible to control when mouse events will be added to the Queue where they are stored and converted into per-sample values. But there are probably efficiencies to be gained in the design of the class I wrote that does this: RTESmoother, with I put in the SampleCode area. I’d be interested in any advice you might have about that code, which can be seen here:http://www.java-gaming.org/topics/an-audio-control-helper-tool-using-a-fifo-buffer/24605/view.html
ACTUALLY (Doh!) based on what I just learned from Neal, a plain array used as a circular queue would be a big pickup. I can overwrite mouse events rather than creating and destroying them!! Must do this. But this will still need a bit of concurrency protection as writes and reads will be occurring potentially at the same time. I’ll post the improved version in the above link.
(2) “Avoid branching” – check, done.
(3) Avoid Java Math functions. – Does this include Math.min() & Math.max()? (I guess, per your next, I should also check for ways to keep the min and max values powers of two.) Otherwise, the only Math function I’m using is Math.sin(), when the WaveTable is first generated. From then on, all references are lookups into this WaveTable.
(4) “Don’t use linked lists to buffer samples…” – check, done, now that I’ve changed the echo to a simple array. That was the only spot. As for the power of two aspect, I will add that. I made my WaveTable 720 samples large as being a multiple of 360 makes the generating math a little easier, but I can see that making it 1024 and doing a bit-level AND operation (vs bounds testing) would be a performance pickup.