Easy C++ Questions

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

syntonica wrote:NO_OF_NODES is a #define.
Oh crap... it's my indices. I just replaced them all with hard values and no crash...
...sigh...

Back to the drawing board... Can I go back to Java now? :ud:

Sorry for my frustration spilling out onto this board. But having to learn a new IDE (Xcode) AND a new language extension (c++) at the same time is driving me spare. It makes me want to kick a puppy at times.
Java would not solve your problem, this is an error in your algorithm that a debugger or valgrind would have also found. Nothing strange here.

And using std::vector is to simplify your memory management. The fact that you don't know that they would be easier for you points to a lack of basic understanding of C++. Stop trying to solve things that you don't understand (as I've said, your DSP code would crash in EXACTLY the same way in Java, so you don't master DSP code either), start with the basics: learn C++11 first.

Post

Max M. wrote:
syntonica wrote:I went through every permutation I could find of how to define a new 2D array.
It can be written w/o a typedef too (if I recall correctly though):

Code: Select all

float (*wave)[1024] = new float[NO_OF_WAVES][1024];
But it's pretty much head-scratching to read even for C++ geeks.
Or even better, don't use C macro, use C++ constants:

const int NO_OF_WAVES = 4;
const int SIZE_OF_WAVES = 1024;

std::array<std::array<float, SIZE_OF_WAVES >, NO_OF_WAVES> waves;

Post

Miles1981 wrote:

Code: Select all

std::array<std::array<float, SIZE_OF_WAVES >, NO_OF_WAVES> waves;
That's not really different from just:

Code: Select all

float waves[NO_OF_WAVES][ SIZE_OF_WAVES];
which I already suggested above:
Max M. wrote:...I suspect the NO_OF_WAVES is a (compile time) constant too, if so you could use the array w/o any new/delete at all (same goes for your coeffs array).

Post

Miles1981 wrote:
Max M. wrote:
syntonica wrote:I went through every permutation I could find of how to define a new 2D array.
It can be written w/o a typedef too (if I recall correctly though):

Code: Select all

float (*wave)[1024] = new float[NO_OF_WAVES][1024];
But it's pretty much head-scratching to read even for C++ geeks.
Or even better, don't use C macro, use C++ constants:

const int NO_OF_WAVES = 4;
const int SIZE_OF_WAVES = 1024;

std::array<std::array<float, SIZE_OF_WAVES >, NO_OF_WAVES> waves;
This last suggestion yields an array of arrays (vector of vectors), with the top level container in a dynamic (heap) allocation and each element of the top level container in a separate container and separate dynamic allocation. This will most likely loose all benefits from CPU caches, and remove the ability to use SSE or other matrix math libraries. What's so hard about:

double * wt = (double *)malloc(NO_OF_WAVES * SIZE_OF_WAVES * SIZEOF(double));

followed by

free(wt);

Writing high performance code in any language requires a thorough understanding of not only the language, but also basic programming, including memory management and object/element life-cycle. That's the problem I have with using Java to teach programming. If you don'r HAVE to learn about memory management, you typically won't.

Post

If you were to take advantage of c++ functionality you would be able to implement bounds checking for such a static array like so:

Code: Select all

template<typename T, int LENGTH>
struct array_t
{
	enum constants
	{
		length = LENGTH,
	};
	
	T &operator[](const int i)
	{
		assert(i >= 0);
		assert(i < length);
		return data[i];
	}
	
	T data[length];
}
You can also allocate the data on the heap if desired. STL and boost implement all of these variations although it is difficult to keep track without an ultra-thick reference for each library. If very simple modules are properly implemented the "roll your own" strategy is to be honest quite often the best option, even if only to avoid using the larger and more complex libraries which despite having greater adaptability also require far more strict obedience to complex rules.

Code: Select all

typedef array_t<float, SIZE_OF_WAVES> wave_t;
typedef array_t<wave_t, NO_OF_WAVES> waves_t;

waves_t waves;
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Thanks all yet again for the replies and great suggestions. I got my debugger out and fixed some stuff, so no more crashes! :clap: But no sound yet. :neutral: I'm finally starting to understand what's going on now.

This debugger is now getting on my nerves, but this is a matter for the Apple boards. :x
Variables held in registers show as NULL and I have to play Guess the Register.

Once I get my sound engine up and running, the I can dive more into learning the c++ libraries and extensions.
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

Ciberithm wrote:....This last suggestion yields an array of arrays (vector of vectors), with the top level container in a dynamic (heap) allocation and each element of the top level container in a separate container and separate dynamic allocation. This will most likely loose all benefits from CPU caches, and remove the ability to use SSE or other matrix math libraries. What's so hard about:

double * wt = (double *)malloc(NO_OF_WAVES * SIZE_OF_WAVES * SIZEOF(double));

followed by

free(wt);
I'm not so familiar with std::array, but the size is a template parameter fixed at compile time. Also it isn't resizable so allocation isnt dynamic.

Your example would work for 1d arrays, but why the c style malloc and not new? For SSE malloc doesnt align the memory correctly. If worried about such things you'd need some kind aligned_malloc depending on the platform

Post

Ciberithm wrote: Writing high performance code in any language requires a thorough understanding of not only the language, but also basic programming, including memory management and object/element life-cycle. That's the problem I have with using Java to teach programming. If you don'r HAVE to learn about memory management, you typically won't.
I needed run anywhere code for a database I wrote, so Java was it and since I never knew where it would run and how fast, the db is all data soup in memory. Since most objects are discarded once out of scope, the Java gc is quite nice, along with the automatic reference counting. You may still leak memory, but it's usually quite small--if any--and you can dispose of objects manually if necessary.

When it comes to stack and heap, I'm more used to setting up data as stack frames rather than mallocking from the heap. Assembler days. When it comes to C, I like to just grab all the heap I need up front and portion it out myself. I don't play well with others. :hihi:

And my biggest error? Calculating note frequencies using ^ instead of pow.... what language am I using again? :lol:
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

aciddose, I remember wishing I had done as you suggest when I got hit by a nasty to locate bug. Best of all is in debug mode VS pads arrays, so I didn't hit the crash till testing in release mode. Apparently it does that to help gather debug information, just not the information that you hit the out of bounds padding it seems....

Anyway that's good advice.

Post

Ciberithm wrote:This last suggestion yields an array of arrays (vector of vectors), with the top level container in a dynamic (heap) allocation and each element of the top level container in a separate container and separate dynamic allocation. This will most likely loose all benefits from CPU caches, and remove the ability to use SSE or other matrix math libraries. What's so hard about:

double * wt = (double *)malloc(NO_OF_WAVES * SIZE_OF_WAVES * SIZEOF(double));

followed by

free(wt);

Writing high performance code in any language requires a thorough understanding of not only the language, but also basic programming, including memory management and object/element life-cycle. That's the problem I have with using Java to teach programming. If you don'r HAVE to learn about memory management, you typically won't.
Well, I guess you don't know your C++ containers. std:array is "allocated" on the stack, not on the heap, so everything is actually aligned as much as possible.
Anyway, to benefit from vectorisation, you need to tag the pointer as restrict. I know how to write high performance code, thank you very much. At least, make it a unique_ptr<double[]> with new.

Post

matt42 wrote:aciddose, I remember wishing I had done as you suggest when I got hit by a nasty to locate bug. Best of all is in debug mode VS pads arrays, so I didn't hit the crash till testing in release mode. Apparently it does that to help gather debug information, just not the information that you hit the out of bounds padding it seems....

Anyway that's good advice.
The C++ containers usually help you there, as they have boundary checks in debug mode (at least the good implementation) and now even for statically-sized arrays :)

Post

Thanks again to everyone for your assistance. My engine is making noise (the FM will strip paint! :o ), and while it sounds like crap for the moment, about 90% works! :hyper: Still gotta fix the modulators and the filters, the easy stuff. ;)
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

Miles1981 wrote:
Ciberithm wrote:This last suggestion yields an array of arrays (vector of vectors), with the top level container in a dynamic (heap) allocation and each element of the top level container in a separate container and separate dynamic allocation. This will most likely loose all benefits from CPU caches, and remove the ability to use SSE or other matrix math libraries. What's so hard about:

double * wt = (double *)malloc(NO_OF_WAVES * SIZE_OF_WAVES * SIZEOF(double));

followed by

free(wt);

Writing high performance code in any language requires a thorough understanding of not only the language, but also basic programming, including memory management and object/element life-cycle. That's the problem I have with using Java to teach programming. If you don'r HAVE to learn about memory management, you typically won't.
Well, I guess you don't know your C++ containers. std:array is "allocated" on the stack, not on the heap, so everything is actually aligned as much as possible.
Anyway, to benefit from vectorisation, you need to tag the pointer as restrict. I know how to write high performance code, thank you very much. At least, make it a unique_ptr<double[]> with new.
Thanks for the attitude - much appreciated. I do know my C++ containers, but never use std::array. I stand corrected in that it does allocate the data on the stack. I also will point out, that in my opinion, large data arrays should not be allocated on the stack. Each C++ runtime has a limit on the amount of data that can be allocated on the stack, and sometimes it is small. That's why I always allocate large data arrays on the heap. I've also seen too many programmers pass pointers to stack allocated structures to threads and wonder why they get segfaults after the method that created the thread exits scope.

Going forward, I'll leave the C++ questions to the C++ gurus, content in knowing that real programmers code in C. :)

Post

Ciberithm wrote:Going forward, I'll leave the C++ questions to the C++ gurus, content in knowing that real programmers code in C. :)
Well, the qttitude is obviously shared, scientific HPC apps are coded in Fortran or C++, no one does that in C any more (because bth languages are definitely faster than C).

Post

Miles1981 wrote:
Ciberithm wrote:Going forward, I'll leave the C++ questions to the C++ gurus, content in knowing that real programmers code in C. :)
Well, the qttitude is obviously shared, scientific HPC apps are coded in Fortran or C++, no one does that in C any more (because bth languages are definitely faster than C).
My statement was not meant to be taken seriously - note the smiley face. :roll:

I hope no one takes your comment about C++ and Fortran being faster than C seriously. First, languages are not fast or slow, code is, so it's really about the implementation of the supporting libraries, many of which are written in assembly code. Fortran can be a very good choice for scientific and high-speed user-space programs, and C++ can be good or bad depending on the implementation. Properly written C++ code can run circles around poorly written C code, even with optimizing compilers. I've seen Java code out perform C/C++, but always because of well written code and efficient libraries.

I'm a Linux kernel developer, who works primarily in C. There is nothing you can do in C++ that I can't do in C, but C++ sure makes many tasks a whole lot easier. When I am in user space, I do code in C++, but don't consider myself a guru. So next time there is a C++ question, I'll let you take it, and if it's regarding C, maybe I'll jump in.

Post Reply

Return to “DSP and Plugin Development”