# C++ Core API: How to get PCM data after dsp processing?

**URL:** https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957
**Category:** FMOD Engine
**Tags:** linux, cpp
**Created:** [March 29, 2021, 2:06pm UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957 "2021-03-29T14:06:33Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![zcguan](https://avatars.discourse-cdn.com/v4/letter/z/f14d63/32.png) [@zcguan](https://qa.fmod.com/u/zcguan)
#### Post date: [March 29, 2021, 2:06pm UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/1 "2021-03-29T14:06:33Z")

</div>

I want to get the raw PCM output data in memory after all the dsp effects rendered, which is used for other processing. Currently, I can only write audios into wav files and read them back as pcm into memory. Due to some network issues in my environment, it costs a lot to write files, read and finally delete them. Is there any method to directly read them into memory?

I found [a demo written in Unity](https://qa.fmod.com/t/get-sound-data-after-dsp-processing/16089/4) but it only defines one callback `CaptureDSPReadCallback`. In the `dsp_custom.cpp` provided in linux examples, it does not have some CaptureDSP **Read** Callback while requires several other callback definitions. How to write a plugin like the one in Unity?

Thanks!

---

<div class="post-metadata">

### Author: ![mathew](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/mathew/32/431_2.png) [@mathew](https://qa.fmod.com/u/mathew)
#### Post date: [March 30, 2021, 12:29am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/2 "2021-03-30T00:29:59Z")

</div>

All of the callbacks shown in the dsp\_custom example are optional, you can set it up simply like the example you found for Unity. For dsp\_custom, you can simply use just myDSPCallback.

---

<div class="post-metadata">

### Author: ![zcguan](https://avatars.discourse-cdn.com/v4/letter/z/f14d63/32.png) [@zcguan](https://qa.fmod.com/u/zcguan)
#### Post date: [March 30, 2021, 1:21am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/3 "2021-03-30T01:21:34Z")

</div>

Thanks!

---

<div class="post-metadata">

### Author: ![zcguan](https://avatars.discourse-cdn.com/v4/letter/z/f14d63/32.png) [@zcguan](https://qa.fmod.com/u/zcguan)
#### Post date: [March 31, 2021, 9:54am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/4 "2021-03-31T09:54:36Z")

</div>

> [@mathew](#):
>
> All of the callbacks shown in the dsp\_custom example are optional, you can set it up simply like the example you found for Unity. For dsp\_custom, you can simply use just myDSPCallback.

I’ve tried to figured out a scratch in c++, but it doesn’t work. I got `FMOD_ERR_INVALID_PARAM` while calling `GetParameterDataCallback`.

First, I add `CreateCallback` and `ReleaseCallback` while the Unity sample does not have. I believe it’s necessary in c++ because I need to manage the memory manually.

Second, I add one `GetParameterDataCallback` to get the plugindata like the `dsp_custom.cpp` example. It is probably where the program failed. I call the `GetParameterDataCallback` in the do-while render loop but get `FMOD_ERR_INVALID_PARAM`. The process also doesn’t enter the `GetParameterDataCallback` function in my debug process. However, I am not aware of which param is wrong.

I am using latest version: 2.01.08.

Here is the c++ scratch I am using now. This sample intends to capture the raw mono pcm data after dsp processing and writes them as a file. I hope it can be useful for others after the problem is solved.

```auto
#include <fstream>
#include "fmod.hpp"
#include "common.h"

typedef struct {
    float *buffer;
    int length_samples;
} mono_pcm;

// This dsp does nothing on audio but copy raw data into data buffer
FMOD_RESULT F_CALLBACK
CaptureDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels,
                   int *outchannels) {
    mono_pcm *data = (mono_pcm *) dsp_state->plugindata;
    for (size_t i = 0; i < length; ++i) {
        outbuffer[i] = inbuffer[i];
        data->buffer[i] = outbuffer[i];
    }
    return FMOD_OK;
}

FMOD_RESULT F_CALLBACK CaptureDSPCreateCallback(FMOD_DSP_STATE *dsp_state) {
    unsigned int blocksize;
    FMOD_RESULT result;
    result = dsp_state->functions->getblocksize(dsp_state, &blocksize);

    // allocate mem for mono_pcm struct
    mono_pcm *data = (mono_pcm *) calloc(sizeof(mono_pcm), 1);
    if (!data) return FMOD_ERR_MEMORY;

    // allocate mem for buffer in mono_pcm
    dsp_state->plugindata = data;
    data->length_samples = blocksize;
    data->buffer = (float *) malloc(blocksize * sizeof(float));
    if (!data->buffer) return FMOD_ERR_MEMORY;
    return FMOD_OK;
}

FMOD_RESULT F_CALLBACK CaptureDSPReleaseCallback(FMOD_DSP_STATE *dsp_state) {
    if (dsp_state->plugindata) {
        mono_pcm *data = (mono_pcm *) dsp_state->plugindata;
        if (data->buffer) free(data->buffer);
        free(data);
    }
    return FMOD_OK;
}

// This api should give access to mono_pcm struct
FMOD_RESULT F_CALLBACK
captureDSPGetParameterDataCallback(FMOD_DSP_STATE *dsp_state, int index, void **data, unsigned int *length, char *) {
    printf("Entered captureDSPGetParameterDataCallback!\n");
    if (index == 0) {
        unsigned int blocksize;
        FMOD_RESULT result;
        mono_pcm *mydata = (mono_pcm *) dsp_state->plugindata;

        result = dsp_state->functions->getblocksize(dsp_state, &blocksize);
        ERRCHECK(result);

        *data = (void *) mydata;
        return FMOD_OK;
    }

    return FMOD_ERR_INVALID_PARAM;
}

int main() {
    FMOD::System *system;
    FMOD::Sound *sound1;
    FMOD::Channel *channel = 0;
    FMOD::DSP *channelhead, *shiftedVocalFader, *captureDSP;
    FMOD::ChannelGroup *masterGroup;
    FMOD_RESULT result;

    FMOD::System_Create(&system);
    system->init(32, FMOD_INIT_NORMAL, 0);

    // open sound
    system->createSound("media/drumloop.wav", FMOD_DEFAULT, 0, &sound1);
    system->playSound(sound1, 0, false, &channel);

    // prepare capture dsp
    FMOD_DSP_DESCRIPTION dspdesc;
    memset(&dspdesc, 0, sizeof(dspdesc));
    strncpy(dspdesc.name, "Capture DSP", sizeof(dspdesc.name));
    dspdesc.numinputbuffers = 1;
    dspdesc.numoutputbuffers = 1;
    dspdesc.read = CaptureDSPCallback;
    dspdesc.create = CaptureDSPCreateCallback;
    dspdesc.release = CaptureDSPReleaseCallback;
    dspdesc.getparameterdata = captureDSPGetParameterDataCallback;
    result = system->createDSP(&dspdesc, &captureDSP);
    ERRCHECK(result);

    // add dsp
    channel->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &channelhead);
    system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &shiftedVocalFader);
    shiftedVocalFader->setActive(true);
    shiftedVocalFader->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 1.8f);

    system->getMasterChannelGroup(&masterGroup);
    result = masterGroup->addDSP(0, captureDSP); // add capture
    ERRCHECK(result);
    masterGroup->addDSP(0, shiftedVocalFader);

    bool isplaying = true;
    mono_pcm *captureData;
    std::ofstream outf("out/captured.pcm", std::ios::binary);
    unsigned int length;
    char valuestr[512];
    do {
        result = system->update();
        ERRCHECK(result);
        channel->isPlaying(&isplaying);
        // cannot get the mono_pcm into captureData: FMOD_ERR_INVALID_PARAM
        result = captureDSP->getParameterData(0, (void **) &captureData, &length, valuestr, 0);
        ERRCHECK(result);
        // failed to write pcm file because captureData == NULL
        outf.write((char *) captureData->buffer, captureData->length_samples * sizeof(float));
    } while (isplaying);

    outf.close();

    result = sound1->release();
    ERRCHECK(result);

    result = masterGroup->removeDSP(captureDSP);
    ERRCHECK(result);
    result = captureDSP->release();
    ERRCHECK(result);

    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);
}

```

---

<div class="post-metadata">

### Author: ![mathew](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/mathew/32/431_2.png) [@mathew](https://qa.fmod.com/u/mathew)
#### Post date: [April 6, 2021, 4:37am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/5 "2021-04-06T04:37:01Z")

</div>

It looks like your plugin description is missing the parameter definitions. For getparameterdata to work, you need to define that parameter. If you look at the dsp\_custom example you will see dspdesc.numparameters and dspdesc.paramdesc are specified. You’ll want to copy this, specifically the wavedata\_desc parameter.

The invalid parameter error you are receiving is because the first parameter to getParameterData is the parameter index and since you haven’t defined any parameters, that index is out of range.

---

<div class="post-metadata">

### Author: ![zcguan](https://avatars.discourse-cdn.com/v4/letter/z/f14d63/32.png) [@zcguan](https://qa.fmod.com/u/zcguan)
#### Post date: [April 6, 2021, 10:07am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/6 "2021-04-06T10:07:39Z")

</div>

Thanks! That is the problem. I thought it is something optional like help message, so I skipped that part.

I fixed it and now the code works. The DSP part:

```cpp
#include <fstream>
#include "fmod.hpp"
#include "common.h"

typedef struct {
    float *buffer;
    int length_samples;
} mono_pcm;

// This dsp does nothing on audio but copy raw data into data buffer
FMOD_RESULT F_CALLBACK
CaptureDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels,
                   int *outchannels) {
    mono_pcm *data = (mono_pcm *) dsp_state->plugindata;
    for (size_t i = 0; i < length; ++i) {
        outbuffer[i] = inbuffer[i];
        data->buffer[i] = outbuffer[i];
    }
    return FMOD_OK;
}

FMOD_RESULT F_CALLBACK CaptureDSPCreateCallback(FMOD_DSP_STATE *dsp_state) {
    unsigned int blocksize;
    FMOD_RESULT result;
    result = dsp_state->functions->getblocksize(dsp_state, &blocksize);

    // allocate mem for mono_pcm struct
    mono_pcm *data = (mono_pcm *) calloc(sizeof(mono_pcm), 1);
    if (!data) return FMOD_ERR_MEMORY;

    // allocate mem for buffer in mono_pcm
    dsp_state->plugindata = data;
    data->length_samples = blocksize;
    data->buffer = (float *) malloc(blocksize * sizeof(float));
    if (!data->buffer) return FMOD_ERR_MEMORY;
    return FMOD_OK;
}

FMOD_RESULT F_CALLBACK CaptureDSPReleaseCallback(FMOD_DSP_STATE *dsp_state) {
    if (dsp_state->plugindata) {
        mono_pcm *data = (mono_pcm *) dsp_state->plugindata;
        if (data->buffer) free(data->buffer);
        free(data);
    }
    return FMOD_OK;
}

// This api should give access to mono_pcm struct
FMOD_RESULT F_CALLBACK
captureDSPGetParameterDataCallback(FMOD_DSP_STATE *dsp_state, int index, void **data, unsigned int *length, char *) {
    if (index == 0) {
        unsigned int blocksize;
        FMOD_RESULT result;
        mono_pcm *mydata = (mono_pcm *) dsp_state->plugindata;

        result = dsp_state->functions->getblocksize(dsp_state, &blocksize);
        ERRCHECK(result);

        *data = (void *) mydata;
        return FMOD_OK;
    }

    return FMOD_ERR_INVALID_PARAM;
}

```

and the main part:

```cpp
int main() {
    FMOD::System *system;
    FMOD::Sound *sound1;
    FMOD::Channel *channel = 0;
    FMOD::DSP *channelhead, *shiftedVocalFader, *captureDSP;
    FMOD::ChannelGroup *masterGroup;
    FMOD_RESULT result;

    FMOD::System_Create(&system);
    system->setOutput(FMOD_OUTPUTTYPE_WAVWRITER_NRT);
    result = system->init(32, FMOD_INIT_NORMAL | FMOD_INIT_PROFILE_ENABLE, (void *) "out/fmod_pitch_shift.wav");

    // open sound
    system->createSound("media/drumloop.wav", FMOD_DEFAULT, 0, &sound1);
    system->playSound(sound1, 0, false, &channel);

    // prepare capture dsp
    FMOD_DSP_PARAMETER_DESC pcmBuffer;
    FMOD_DSP_PARAMETER_DESC *captureDSPParamDescs[1] =
            {
                    &pcmBuffer,
            };

    FMOD_DSP_INIT_PARAMDESC_DATA(pcmBuffer, "pcm data", "", "pcm data", FMOD_DSP_PARAMETER_DATA_TYPE_USER);

    FMOD_DSP_DESCRIPTION dspdesc;
    memset(&dspdesc, 0, sizeof(dspdesc));
    strncpy(dspdesc.name, "Capture DSP", sizeof(dspdesc.name));
    dspdesc.numinputbuffers = 1;
    dspdesc.numoutputbuffers = 1;
    dspdesc.read = CaptureDSPCallback;
    dspdesc.create = CaptureDSPCreateCallback;
    dspdesc.release = CaptureDSPReleaseCallback;
    dspdesc.getparameterdata = captureDSPGetParameterDataCallback;
    dspdesc.numparameters = 1;
    dspdesc.paramdesc = captureDSPParamDescs;
    result = system->createDSP(&dspdesc, &captureDSP);
    ERRCHECK(result);

    // add dsp
    channel->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &channelhead);
    system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &shiftedVocalFader);
    shiftedVocalFader->setActive(true);
    shiftedVocalFader->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 1.8f);

    system->getMasterChannelGroup(&masterGroup);
    masterGroup->addDSP(0, shiftedVocalFader);
    result = masterGroup->addDSP(0, captureDSP); // add capture
    ERRCHECK(result);

    bool isplaying = true;
    mono_pcm *captureData;
    std::ofstream outf("out/captured.pcm", std::ios::binary);
    unsigned int length, bufferlength;
    char valuestr[512];
    system->getDSPBufferSize(&bufferlength, 0);

    do {
        result = system->update();
        ERRCHECK(result);
        channel->isPlaying(&isplaying);
        result = captureDSP->getParameterData(0, (void **) &captureData, &length, valuestr, 0);
        ERRCHECK(result);
        outf.write((char *) captureData->buffer, captureData->length_samples * sizeof(float));
    } while (isplaying);

    outf.close();

    result = sound1->release();
    ERRCHECK(result);

    result = masterGroup->removeDSP(captureDSP);
    ERRCHECK(result);
    result = captureDSP->release();
    ERRCHECK(result);

    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);
}

```

---

<div class="post-metadata">

### Author: ![FineJared8](https://avatars.discourse-cdn.com/v4/letter/f/e19adc/32.png) [@FineJared8](https://qa.fmod.com/u/FineJared8)
#### Post date: [August 25, 2022, 10:46am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/7 "2022-08-25T10:46:50Z")

</div>

how to process PCM data without playing sound.

---

<div class="post-metadata">

### Author: ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)
#### Post date: [August 29, 2022, 2:19am UTC](https://qa.fmod.com/t/c-core-api-how-to-get-pcm-data-after-dsp-processing/16957/8 "2022-08-29T02:19:04Z")

</div>

Linking into this discussion [Adjust the sound effect without playing the sound - #2 by jeff\_fmod](https://qa.fmod.com/t/adjust-the-sound-effect-without-playing-the-sound/19186/2)
