[music-dsp] Re: A Collection of C++ Classes for Digital Signal
Processing
Vinnie
thevinn at yahoo.com
Mon May 4 06:05:17 EDT 2009
> From: "Martin Eisenberg"
> The DF2 is numerically inferior to DF2-transposed which is
> what you should implement.
Can you please give me a link? All I could find were the diagrams and I have trouble reading those.
> Besides, the current code is broken,
> as a statement like "a = b = c;" just gives both a and
> b the value of c, it does not shift the values.
I guess you are talking about
CalcT d2=h->v[2]=h->v[1];
CalcT d1=h->v[1]=h->v[0];
These statements seem to be working fine. v[1]->v[2] and v[0]->v[1] which is exactly what is intended. d1 and d2 get copies in registers for computation. And it sounds great! This was all tested in a production application with real audio data.
> I don't get what the problem with <complex> is --
> after all you don't reimplement the required subset of <cmath>
> either.
What do you mean by required subset? I wanted a complex class that was under my control. At some point I will be using approximations for the trigonometric functions in the ComplexT class itself. Especially for operations like ::sqrt().
> On the other hand, if I'm going to filter complex data then
> probably I already have a complex class in use (and chances are
> it's std::complex), so your decision means some hassle for me.
Say what? You mean run the filter on an array of complex numbers? I did not know that was a use case. I'm not sure my code supports that. It definitely doesn't work with integers as the underlying type. I wouldn't even know how to test such a thing to see if it sounded right.
But regardless, if you wanted to run the filter on complex numbers and it somehow works I don't see a problem. You can still use std::complex as template parameter T, its just that the pole computations will use ComplexT.
> This contains several things that really don't depend
> on the template parameters (or at least not on their being
> statically known).
Yes I see what you mean. There is also the problem that if one wanted to dynamically choose the number of poles at runtime it could be a bit unwieldly to use. I will try to factor the class a bit better.
> Move those things into a non-template base class to
> reduce code bloat.
When you say code bloat do you mean the generated code? Shouldn't the compiler know when a method doesn't truly depend on template parameters and just emit one copy for all instantiations?
> I'm also not convinced of the value
> in making "skip" a template parameter.
Do you mean it should be a paramter to the function with a default value of 0? Thats a good idea. Or do you mean that having 'skip' is unneccesary? I feel that it is necessary for the case where one wishes to process only a subset of multichannel data. Having it as a parameter would be helpful though, I will change it. Thanks!
> | // ALL SSE OPTIMIZATIONS ASSUME CalcT as double
>
> Then I should be unable to run them differently to begin
> with. Insert a compile-time assertion to that effect in the
> relevant CascadeFilter section.
I agree 100%. My C++/template knowledge has gaps though. How exactly do I write a compile-time assertion to check CalcT==double? I would also like to provide SSE implementation where CalcT is float, how would I do that?
There's also that annoying warning about "conditional expression is constant" in ProcessI() where I do the following:
#ifdef SSE3_OPTIMIZED
if( channels==2 )
ProcessISSE2<skip>( frames, dest );
else
#endif
I wanted to do this using a partial template specialization but that is either impossible, MSVC doesn't support it, or I just don't know the syntax. How can I specialize just one parameter from the template? Specifically if I have
template<int stages, int channels>
template<int skip, typename T>
void CascadeFilter<stages, channels>::ProcessI( size_t frames, T *dest );
And I want to provide a version where stages is configurable but channels is 2 how do I do that? This doesn't work:
template<int stages, int channels=2>
template<int skip, typename T>
void CascadeFilter<stages, channels>::ProcessI( size_t frames, T *dest )
Nor does this
template<int stages>
template<int skip, typename T>
void CascadeFilter<stages, 2>::ProcessI( size_t frames, T *dest )
And finally as you pointed out some routines don't depend on the template arguments. In fact, the Process() functions certainly don't. stages and channels could be simply passed in as parameters, with default values from the derived template class' stages and channels template parameters.
I will take everything you described under consideration and make some changes.
More information about the music-dsp
mailing list