Answered
0
0

Hi

In Fmod ex you had a command FMOD_System_AddDSP or System::AddDSP, but which has been removed in FMOD5. So what command should I now use instead?

Thanks in advance

Sincerely

Keitel

  • You must to post comments
Good Answer
2
0

To get the same result in FMOD 5 query the master channel group from the System object and add the DSP to it instead.

  • You must to post comments
1
0

This is your bug

dpdesc.userdata     = (void *)0x12345678; 

followed by this in the callback

FMOD_DSP_GetUserData(thisdsp, (void **)&userdata);

and

ret = DiracProcessInterleaved(outbuffer, length, (void*)userdata);

you have not stored the direct handle, you have stored 0x12345678

There’s also an example in the Dirac folder that is specifically for FMOD. –DIRAC3LE–\Dirac3-Desktop\DiracFMOD and it uses the correct setup, ie

dspdesc.userdata = (void *)dirac;
  • Brett Paterson
    Hi Ketil. I've checked into this. playDSP would be the best way to do it, but it looks like there is a bug where the dsp is not transferring its channel count to the resampler. I'll try to get this into a build which goes out in the next day or 2.
  • Brett Paterson
    Another way to fix it is to use process callback instead of read callback, and make sure the process FMOD_DSP_PROCESS_QUERY mode gets the right number of channels back. Using read callback, it is getting 0 channels back at the moment which is the reason for the issue.
  • Ketil Helmersberg
    Hi again, I have recompiled the program with your last Fmod version, but I still have one issue, though I don’t know if it is directly related to Fmod or something else. I have transferred the console application to become a function in a Windows API program, just making the necessary adjustments. When I include the command FMOD_System_PlayDSP(systemx, mydsp, channelgroup, 0, &channel[1]) in the function, the program exits with the debug message Native' has exited with code -1 (0xffffffff). However, when I put a system("pause") command after the PlayDSP command it works, but then I also get the additional console application window. I see no reason why the program should exit, as it doesn’t do so when I remove the PlayDSP command. I therefore wonder if you could give me an idea what could be wrong? Keitel
  • Ketil Helmersberg
    I guess I'll have to use a thread function. But if I then want to play more than one file like this simultaneously, don't I then have to make two thread functions?
  • Brett Paterson
    It really sounds to me like your program just exited because you didnt wait for input. I dont see why you would need a thread, or think you need threads to play sounds? FMOD has a playsound command, you just call them one after the other. The standard way to make a windows program is to respond to messages, or run a main loop in winmain and translate and dispatch the necessary windows messages as they come in (you still need to do this either way), but in between this stuff, call your game code update function, which would be calling fmod functions. Have you written a windows program before? This is starting to get off topic for FMOD Q/A but there are plenty of resources online to get you started.
0
0

Thank you for your answer. So I’ve put it like this in my program:

FMOD_DSP *mydsp;
FMOD_CHANNELGROUP *channelgroup;

FMOD_System_GetMasterChannelGroup(system, &channelgroup);

FMOD_ChannelGroup_AddDSP(channelgroup,0, mydsp);

I guess it’s correct. However, every time the program comes to the FMOD_ChannelGroup_AddDSP command, it stops or exits. Do you think you could give me any idea why this happens.

Sincerely

Keitel

  • Mathew Block
    Are you getting an error code back which is causing the exit? Or does the code crash?
  • You must to post comments
0
0

The code crashes, so I don’t get any error code.

Keitel

  • Mathew Block
    Can you show us the code you are using to create your DSP object before passing into addDSP?
  • You must to post comments
0
0

The code I am trying out is from the website of Dirac, combining Dirac with Fmod.

http://www.dspdimension.com/admin/using-dirac-with-fmod-to-change-pitch-and-speed-of-audio-in-real-time/

This code again is based on one of Fmod’s example programs, “dsp_custom.” The code is, however, obviously made for Fmod ex, and I have tried to translate it, from the Dirac site, from C++ to C and to compatibility with Fmod5.

As known, Dirac can change pitch of a sound file without changing its speed, and change the speed without changing the pitch. However, it is not by itself able to simultaneously retain a perfect loop of a sound file. So, if I have understood it correctly, that is the purpose of this program, though I myself only understand parts of the code in detail.

While the original code in C++ can be found at the Dirac website, the code below is my edited version:

    /*===============================================================================================
 Dirac Time Stretching Example
 Copyright (c), Firelight Technologies Pty, Ltd 2004-2011.
 Copyright (c), The DSP Dimension 2012

 This example shows how to use Dirac to change pitch and speed of music independently from
 each other during playback by using FMOD's sound streaming capabilities.

 This demo inserts a custom DSP callback into the FMOD signal chain and pulls audio data from 
 the input sound through that callback for processing.

 Several other implementations are possible, but this appears to offer the best trade off 
 between code complexity and realtime performance.

 Note that using the DiracFx API would provide even better performance but it would mean
 sacrificing some audio quality in the process.

 Note also that unlike the FMOD stream engine we do not insert a resampler into the signal
 chain. If the file's sample rate does not match the system's sample rate your file will
 play at the wrong speed and sound out of tune. You can use Dirac to correct for this, but
 we left that part out of the code to keep it more readable.

===============================================================================================*/

    #include <conio.h>
    #include "fmod.h"
    #include "fmod_errors.h"
    #include <windows.h>
    #include <stdio.h>
    #include <math.h>

    #include "stdafx.h"
    typedef signed int        int32_t;
    //#define   SOUNDFILE_PATH      "./local_media/test-loop.wav"

    #define SOUNDFILE_PATH      "tamp4.wav"

    #include "Dirac.h"

/* ****************************************************************************
    Set up some handy constants
 **************************************************************************** */
const float div8 = 0.0078125f;          //1./pow(2., 8.-1.);
const double div16 = 0.00003051757812;  //1./pow(2., 16.-1.);
const double div32 = 0.00000000046566;  //1./pow(2., 32.-1.);

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/* ****************************************************************************
    This is the struct that holds state variables that our callback needs. In
    your program you will want to replace this by a pointer to "this" in order
    to access your instance methods and member variables
 **************************************************************************** */
typedef struct {
    unsigned int sReadPosition, sFileNumFrames;
    int sNumChannels, sNumBits;
    FMOD_SOUND  *sSound;
} userDataStruct;

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void ERRCHECK(FMOD_RESULT result)
{
    if (result != FMOD_OK)
    {
        printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
        exit(-1);
    }
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------------

/* ****************************************************************************
    This converts the raw format from the decoded file to the float format that
    Dirac expects. 
 **************************************************************************** */
static void intToFloat(float *dest, void *src, long size, int wordlength)
{
    int32_t *v;
    long wordlengthInBytes = wordlength / 8;
    long numElementsInBuffer = size / wordlengthInBytes;
    long i;
    switch (wordlength) {
        case 8:
        {
            signed char *v = (signed char *)src;
            for ( i = 0; i < numElementsInBuffer; i++)  
                dest[i]=(float)v[i] * div8;
        }
            break;
        case 16:
        {
            signed short *v = (signed short *)src;  
            for ( i = 0; i < numElementsInBuffer; i++) {
                dest[i]=(float)v[i] * div16;
            }
        }
            break;
        case 24:
        {
            unsigned char *v = (unsigned char *)src;
            long c = 0;
            for ( i = 0; i < numElementsInBuffer; i++)  {
                int32_t value = 0;
                unsigned char *valuePtr = (unsigned char *)&value;

                valuePtr[0] = 0;
                valuePtr[1] = v[c]; c++;
                valuePtr[2] = v[c]; c++;
                valuePtr[3] = v[c]; c++;

                dest[i]=(double)value * div32;
            }
        }
            break;
        case 32:
        {
            printf("!!! 32bit files are not fully supported. Trying anyway...\n");
#if 0 /* this correctly plays 32 bit AIFF files but not WAV. Byte swapping bug in FMOD? */
            unsigned char *v = (unsigned char *)src;
            long c = 0;
            for (long i = 0; i < numElementsInBuffer; i++) {
                int32_t value = 0;
                unsigned char *valuePtr = (unsigned char *)&value;

                valuePtr[3] = v[c]; c++;
                valuePtr[2] = v[c]; c++;
                valuePtr[1] = v[c]; c++;
                valuePtr[0] = v[c]; c++;

                dest[i]=(double)value * div32;
            }
#else /* this correctly plays 32bit WAV files but not AIFF. Byte swapping bug in FMOD? */

            v = (int32_t *)src; 
            for ( i = 0; i < numElementsInBuffer; i++) {
                dest[i]=(double)v[i] * div32;
            }
#endif

        }
            break;
        default:
            break;
    }
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/* ****************************************************************************
    Reads a chunk of raw audio from the FMOD sound. If the read access was
    successful we convert the data to float
 **************************************************************************** */
int readFromSound(float *targetBuffer, unsigned int startFrame, unsigned int numFrames, FMOD_SOUND *sound, int numBits, int numChannels)
{
    void  *data1 = NULL;
    void  *data2 = NULL;
    unsigned int length1;
    unsigned int length2;

    int ret = -1;

    int framesToBytes = numChannels * numBits / 8;

    // lock the buffer

    FMOD_Sound_Lock(sound, startFrame * framesToBytes, numFrames * framesToBytes, &data1, &data2, &length1, &length2);

    if (data1)
        intToFloat(targetBuffer, data1, length1, numBits);

    // unlock the buffer once you're done
    FMOD_Sound_Unlock(sound, data1, data2, length1, length2);   
    return ret;
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/* ****************************************************************************
    This is the callback function that supplies data from the input stream/file
    when needed by Dirac. The read requests are *always* consecutive, ie. the 
    routine will never have to supply data out of order.
    Should return the number of frames read, 0 when EOF, and -1 on error.
 **************************************************************************** */
long diracDataProviderCallback(float *chdata, long numFrames, void *userData)
{   
    unsigned int framesToReadBeforeEndOfFile = 0;
    userDataStruct *state;
    FMOD_SOUND *mySound;

    // The userData parameter can be used to pass information about the caller (for example, "this") to
    // the callback so it can manage its audio streams.

    if (!chdata)    return 0;

    state = (userDataStruct*)userData;
    if (!state) return 0;

    mySound = state->sSound;


    // demonstrates how to loop our sound seamlessly when the file is done playing:
    // 
    // we have this many frames left before we hit EOF


    // if our current read position plus the required amount of frames takes us past the end of the file
    if (state->sReadPosition + numFrames > state->sFileNumFrames) {

        // we have this many frames left until EOF
        framesToReadBeforeEndOfFile = state->sFileNumFrames-state->sReadPosition;

        // read the remaining frames until EOF
        readFromSound(chdata, state->sReadPosition, framesToReadBeforeEndOfFile, mySound, state->sNumBits, state->sNumChannels);

        // rewind the file
        state->sReadPosition = 0;

        // remove the amount we just read from the amount that we actually want
        numFrames -= framesToReadBeforeEndOfFile;
    }

    // here we read the second part of the buffer (in case we hit EOF along the way), or just a chunk of audio from the file (in case we have not encountered EOF yet)
    readFromSound(chdata+framesToReadBeforeEndOfFile*state->sNumChannels, state->sReadPosition, numFrames, mySound, state->sNumBits, state->sNumChannels);
    state->sReadPosition += numFrames;

    return numFrames;   

}

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/* ****************************************************************************
    This is our custom dsp callback as implemented by the FMOD example
    dsp_custom. 
 **************************************************************************** */
FMOD_RESULT F_CALLBACK myDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels) 
{ 
    unsigned int userdata;
    char name[256]; 
    FMOD_DSP *thisdsp = (FMOD_DSP *)dsp_state->instance;

    int ret = kDiracErrorNoErr;

    /* 
        This redundant call just shows using the instance parameter of FMOD_DSP_STATE and using it to 
        call a DSP information function. 
    */

    FMOD_DSP_GetInfo(thisdsp, name, 0, 0, 0, 0);

    //thisdsp->getInfo(name, 0, 0, 0, 0);

    // userData points to our Dirac instance

    FMOD_DSP_GetUserData(thisdsp, (void **)&userdata);

    //thisdsp->getUserData((void **)&userdata);

    if (!userdata)
        return FMOD_ERR_NOTREADY;

    ret = DiracProcessInterleaved(outbuffer, length, (void*)userdata);

    switch (ret) {
        case kDiracErrorDemoTimeoutReached:
            printf("!!! Dirac Evaluation has reached its demo timeout\n\tSwitching to BYPASS\n");

            FMOD_DSP_SetBypass(thisdsp, true);

            //thisdsp->setBypass(true);
            break;
        default:
            break;
    }

    return FMOD_OK; 
} 

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

int main(int argc, char *argv[])
{
    FMOD_SYSTEM       *system;
    FMOD_SOUND        *sound;
    FMOD_CHANNEL      *channel;
    FMOD_DSP          *mydsp;
    FMOD_RESULT        result;
    char               key = 'c';
    unsigned int        version;
    int                 sampleRate;

    void *dirac;

    float time;
    float pitch;

    static bool active;

    FMOD_DSP_DESCRIPTION  dspdesc; 

    FMOD_CHANNELGROUP *channelgroup;

    userDataStruct state;
    state.sReadPosition;
    state.sSound;



    /*
        Create a System object and initialize.
    */
    result = FMOD_System_Create(&system);
    ERRCHECK(result);

    result = FMOD_System_GetVersion(system, &version);
    ERRCHECK(result);

    if (version < FMOD_VERSION)
    {
        printf("Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION);
        return 0;
    }

    result = FMOD_System_Init(system, 32, FMOD_INIT_NORMAL, 0);
    ERRCHECK(result);

    // get the output (=processing) sample rate from the system
    // actually, we should use the file's sample rate, but I'm not sure if there is a call for that in FMOD
    result = FMOD_System_GetSoftwareFormat(system, &sampleRate, NULL, NULL);
    ERRCHECK(result);


    result = FMOD_System_CreateSound(system, SOUNDFILE_PATH, FMOD_LOOP_NORMAL, 0, &sound);

    ERRCHECK(result);

    printf("===============================================================================\n");
    printf("Dirac DSP example. Copyright (c) Firelight Technologies 2004-2011 and \n");
    printf("(c) 2012 The DSP Dimension, Stephan M. Bernsee \n");
    printf("===============================================================================\n");
    printf("Press 'f' to activate, deactivate Dirac\n");
    printf("Press 'Esc' to quit\n");
    printf("\n");


    /* ****************************************************************************
        DIRAC SETUP
        -----------
        We put all of Dirac's state variables that we need to access later in a
        struct. In a C++ program you will normally pass your instance pointer
        "this" as Dirac userData, but since this is not a class we cannot do 
        this here
     **************************************************************************** */
    state.sReadPosition = 0;
    state.sSound = sound;

    // obtain the length of the sound in sample frames (needed to loop the sound properly)

    FMOD_Sound_GetLength(sound, &state.sFileNumFrames, FMOD_TIMEUNIT_PCM);

    //result = sound->getLength(&state.sFileNumFrames, FMOD_TIMEUNIT_PCM);
    ERRCHECK(result);

    // get the number of channels and number of bits. Needed to obtain the correct seek position in the file when using Sound::lock

    FMOD_Sound_GetFormat(sound, NULL, NULL, &state.sNumChannels, &state.sNumBits);

    ERRCHECK(result);

    // create our Dirac instance. We use the fastest possible setting for the Dirac core API here

    dirac = DiracCreateInterleaved(kDiracLambdaPreview, kDiracQualityPreview, state.sNumChannels, sampleRate, &diracDataProviderCallback, (void*)&state);
    if (!dirac) {
        printf("!! ERROR !!\n\n\tCould not create DIRAC instance\n\tCheck number of channels and sample rate!\n");
        exit(-1);
    }

    // Here we set our time stretch an pitch shift values
    time      = 1.0f;                   // 125% length
    pitch     = 0.5f;       // pitch shift (0 semitones)

    // Pass the values to our DIRAC instance    
    DiracSetProperty(kDiracPropertyTimeFactor, time, dirac);
    DiracSetProperty(kDiracPropertyPitchFactor, pitch, dirac);

    // Print our settings to the console
    DiracPrintSettings(dirac);

    printf("Running DIRAC version %s\nStarting processing\n", DiracVersion());

    // start playback

    result = FMOD_System_PlaySound(system, sound, NULL, false, &channel);

    ERRCHECK(result);

    /*
        Create the DSP effects.
    */  

   { 
        FMOD_DSP_DESCRIPTION  dspdesc; 

        memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); 

        strcpy(dspdesc.name, "My first DSP unit"); 

    dspdesc.numinputbuffers     = 0;                   // 0 = whatever comes in, else specify.   These two has to be checked ????

    dspdesc.read         = &myDSPCallback; 
        dspdesc.userdata     = (void *)0x12345678; 

        result = FMOD_System_CreateDSP(system, &dspdesc, &mydsp); 
        ERRCHECK(result); 
    } 

    /*
        Inactive by default.
    */

    active = false;

    FMOD_DSP_SetBypass(mydsp, active);


    /*
        Main loop.
    */


   result = FMOD_System_GetMasterChannelGroup(system, &channelgroup);

   result = FMOD_ChannelGroup_AddDSP(channelgroup,0, mydsp);


   ERRCHECK(result); 


   if (result != FMOD_OK)
    {
        printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
        exit(-1);
    }

    /*
        Main loop.
    */
    do
    {
        if (kbhit())
        {
            key = _getch();

            switch (key)
            {
                case 'f' : 
                case 'F' : 
                {
                    active = !active;
                    FMOD_DSP_SetBypass(mydsp, active);
                    if (!active)    printf("\nProcessing with Dirac\n");
                    else            printf("\nBYPASS ON\n");
                    break;
                }
            }
        }

        FMOD_System_Update(system);

        Sleep(10);

    } while (key != 'a');

    printf("\n");

    result = FMOD_Sound_Release(sound);
    ERRCHECK(result);

    result = FMOD_DSP_Release(mydsp);
    ERRCHECK(result);

    result = FMOD_System_Close(system);
    ERRCHECK(result);
    result = FMOD_System_Release(system);
    ERRCHECK(result);

    DiracDestroy(dirac);

    return 0;
}

Thanks in advance.

Keitel

  • Nicholas Wilcox
    What compiler are you using? Can you try deleting the first "FMOD_DSP_DESCRIPTION dspdesc" and changing the second to "static FMOD_DSP_DESCRIPTION dspdesc".
  • Ketil Helmersberg
    I am using Microsoft Visual C++ 2010 Express with Windows 7. I tried your suggestion, but it didn't change the situation. Keitel
  • You must to post comments
0
0

I am using Microsoft Visual C++ 2010 Express with Windows 7. I tried your suggestion, but it didn’t change the situation.

Keitel

  • You must to post comments
0
0

Hi Brett!
No, no, this must be a misunderstanding. I know how to program in C for Windows and how to make sounds with Fmod. Though I admit that my understanding of the DSP functionalities is somewhat limited. The issue is that I have a function with a playDSP command that I call from the main program. But when I call the function an it reaches the playDSP command, the proram exits. It might be because of some triviality that I have overlooked, but I am not able to see that for now. So if you could take a look at the code of the function below, and see if you can find anything wrong, it would appreciate it very much. The other functions that is called by this function is the same as in the previous examples.

void timestretch(int selection, float time, float pitch, char infileName[]){

FMOD_DSP                *mydsp;
FMOD_CHANNELGROUP   *channelgroup;
    void                        *dirac;

userDataStruct state;
state.sReadPosition;
state.sSound;

result = FMOD_System_GetSoftwareFormat(systemx, &sampleRate, NULL, NULL);   
result = FMOD_System_CreateSound(systemx, infileName, FMOD_LOOP_NORMAL, 0, &sound[selection]);
ERRCHECK(result);

state.sReadPosition = 0;
state.sSound = sound[selection];

result = FMOD_Sound_GetLength(sound[selection], &state.sFileNumFrames, FMOD_TIMEUNIT_PCM);

ERRCHECK(result);

result = FMOD_Sound_GetFormat(sound[selection], NULL, NULL, &state.sNumChannels, &state.sNumBits);

ERRCHECK(result);

dirac = DiracCreateInterleaved(kDiracLambdaPreview, kDiracQualityPreview, state.sNumChannels, sampleRate, &diracDataProviderCallback, (void*)&state);

{ 
    static FMOD_DSP_DESCRIPTION  dspdesc; 

    memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); 

    strcpy(dspdesc.name, "My first DSP unit");      

    dspdesc.numinputbuffers     = 0;                

    dspdesc.read         = &myDSPCallback; 
            dspdesc.userdata     = (void *)dirac; 

    result = FMOD_System_CreateDSP(systemx, &dspdesc, &mydsp); 
    ERRCHECK(result); 
    } 

FMOD_System_Update(systemx);

result = FMOD_System_GetMasterChannelGroup(systemx, &channelgroup);

ERRCHECK(result);

result = FMOD_System_PlayDSP(systemx, mydsp, channelgroup, 0, &channel[1]);

   ERRCHECK(result);    

   FMOD_System_Update(systemx);

}

Thanks in advance.

Keitel

  • Ketil Helmersberg
    When debugging with the above code; I get the following error message: Unhandled exception at 0x75c8812f (KernelBase.dll) in DhruvaNada2.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0026f068.. Keitel
  • Ketil Helmersberg
    I made the "state" variable into a global variable and then it worked. I therefore consider the case solved. Thanks for all help and support. -Keitel
  • You must to post comments
Showing 7 results
Your Answer

Please first to submit.