Storing Sample Values

Apologies if this should be simple…

I’m trying to store some sample values manually. How is the correct way to do the below example which doesn’t work?

  sample** smp = {0};

  for (int s = 0; s < nFrames; s++)  {
	for (int c = 0; c < nChans; c++) {

	  if (inputs[c][s] > smp[0][0])
            smp[0][0] = inputs[c][s];
	}
  }

Sorry for the awful code - sample** has really thrown me…

Thanks,
James

Pointers are notoriously difficult to understand, and double pointers are even harder! :slight_smile:

A pointer is a kind of variable that stores a memory address - it points to some memory. It is similar to a reference, except that a reference cannot be null, it must reference something (reference variables use the ampersand rather than asterisk - e.g. sample& ). A memory address is an integer that indicates where in the current process’ memory space something is. So a sample* is a pointer to a variable of type sample. It stores the address at which the sample value is stored. The sample type could either be a 32 bit or a 64 bit floating point value.

Arguments like sample** inputs are typically used when a function/method is intended to process multi-channel buffers of samples. For each channel of audio there are nFrames samples stored contiguously in an array. The sample** double pointer points to a multi-dimensional array, where the first access the channel and the second access the sample in a particular channel.

When you want to store samples you need to create a variable of type sample (or an array of samples), not a pointer to a sample (sample*) and not double pointer (sample**). Typically you would do something like this:

// assume nFrames = 512, nChans = 2
sample smp[1024] = {0.0}; // an array of 1024 samples
sample* smpPtrs[2] = {&smp, &smp + 512}; // an array of two pointers to samples, pointing into smp

for (int s = 0; s < 512; s++) {
    for (int c = 0; c < 2; c++) {
        smpPtrs[c][s] = inputs[c][s]; // copy input sample
    }
}

Not tested this code, but hopefully it helps

Legend thanks @olilarkin.

Just a follow up question on memory though…

If I then send this pointer to mSender.ProcessBlock, am I right that the pointer will be duplicated when sent, and the original destroyed when the function scope ends. Then the duplicate will be destroyed when OnMsgFromDelegate is out of scope? (Even if this is indirectly)

I guess what I’m really asking is, is there any chance of memory leakage, do I need to use something like smart ptrs?

Thanks again!

Scope is important here, “Smart Pointers” are not…

Assuming the smp and smpPtrs variables are in MyPlugin::ProcessBlock() they will only exist in the scope of that method. If you call mSender.ProcessBlock(smpPtrs, nFrames) in that method, it should work without crashing, because the sender copies the data into its own buffers. If you were to allocate the smp memory on the heap (which would be bad in a realtime method), then you would need to be sure it was freed when the variable goes out of scope, or else you’d have a memory leak.

It is more common that if you need to “store” significant numbers of samples, you would create a member variable with heap-allocated memory, using std::vector or WDL_TypedBuf.

1 Like

Understood. Thanks again, Oli!