Custom codec - FMOD_ERR_PLUGIN_VERSION


#1

I’m trying to write a custom codec for project, using the fmod_codec_raw.cpp example as a base to work from. Everything compiles fine, however when I attempt to create a sound, it gives an error that the plugin was built using the wrong version of fmod - which is odd, as the codec code is compiled in the same source file as the code that is using other fmod API features.

To check if it was my code or something else, I tried the same thing with the load_from_memory sample, and copied the code from fmod_codec_raw.cpp into the load_from_memory.cpp. Upon trying to call createSound, the result code from createSound is FMOD_ERR_PLUGIN_VERSION (56).

The rawopen callback function is returning FMOD_OK.

Does anyone know how I might be able to resolve this issue please? Partial/relevant sample code from the example cpp follows:

#include "fmod.hpp"
#include "common.h"

static FMOD_CODEC_WAVEFORMAT    rawwaveformat;

/*
The actual codec code.

Note that the callbacks uses FMOD's supplied file system callbacks.

This is important as even though you might want to open the file yourself, you would lose the following benefits.
1. Automatic support of memory files, CDDA based files, and HTTP/TCPIP based files.
2. "fileoffset" / "length" support when user calls System::createSound with FMOD_CREATESOUNDEXINFO structure.
3. Buffered file access.
FMOD files are high level abstracts that support all sorts of 'file', they are not just disk file handles.
If you want FMOD to use your own filesystem (and potentially lose the above benefits) use System::setFileSystem.
*/

FMOD_RESULT F_CALLBACK rawopen( FMOD_CODEC_STATE *codec, FMOD_MODE /*usermode*/, FMOD_CREATESOUNDEXINFO * /*userexinfo*/ )
{
  rawwaveformat.channels = 2;
  rawwaveformat.format = FMOD_SOUND_FORMAT_PCM16;
  rawwaveformat.frequency = 44100;
  rawwaveformat.pcmblocksize = 0;
  rawwaveformat.lengthpcm = codec->filesize / ( rawwaveformat.channels * sizeof( short ) );   /* bytes converted to PCM samples */;

  codec->numsubsounds = 0;                    /* number of 'subsounds' in this sound.  For most codecs this is 0, only multi sound codecs such as FSB or CDDA have subsounds. */
  codec->waveformat = &rawwaveformat;
  codec->plugindata = 0;                    /* user data value */

                                            /* If your file format needs to read data to determine the format and load metadata, do so here with codec->fileread/fileseek function pointers.  This will handle reading from disk/memory or internet. */

  return FMOD_OK;
}

FMOD_RESULT F_CALLBACK rawclose( FMOD_CODEC_STATE * /*codec*/ )
{
  return FMOD_OK;
}

FMOD_RESULT F_CALLBACK rawread( FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read )
{
  return codec->fileread( codec->filehandle, buffer, size, read, 0 );
}

FMOD_RESULT F_CALLBACK rawsetposition( FMOD_CODEC_STATE *codec, int /*subsound*/, unsigned int position, FMOD_TIMEUNIT /*postype*/ )
{
  return codec->fileseek( codec->filehandle, position, 0 );
}


FMOD_CODEC_DESCRIPTION rawcodec =
{
  "FMOD Raw player plugin example",   // Name.
  0x00010000,                         // Version 0xAAAABBBB   A = major, B = minor.
  0,                                  // Don't force everything using this codec to be a stream
  FMOD_TIMEUNIT_PCMBYTES,             // The time format we would like to accept into setposition/getposition.
  &rawopen,                           // Open callback.
  &rawclose,                          // Close callback.
  &rawread,                           // Read callback.
  0,                                  // Getlength callback.  (If not specified FMOD return the length in FMOD_TIMEUNIT_PCM, FMOD_TIMEUNIT_MS or FMOD_TIMEUNIT_PCMBYTES units based on the lengthpcm member of the FMOD_CODEC structure).
  &rawsetposition,                    // Setposition callback.
  0,                                  // Getposition callback. (only used for timeunit types that are not FMOD_TIMEUNIT_PCM, FMOD_TIMEUNIT_MS and FMOD_TIMEUNIT_PCMBYTES).
  0                                   // Sound create callback (don't need it)
};

int FMOD_Main()
{
    FMOD::System     *system;
    FMOD::Sound      *sound1, *sound2, *sound3;
    FMOD::Channel    *channel = 0;
    FMOD_RESULT       result;
    unsigned int      version;
    void             *extradriverdata = 0;
    void             *buff = 0;
    int               length = 0;
    FMOD_CREATESOUNDEXINFO exinfo;
    unsigned int      codecHandle;
    
    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->getVersion(&version);
    ERRCHECK(result);

    if (version < FMOD_VERSION)
    {
        Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION);
    }

    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);
    
    result = system->registerCodec( &rawcodec, &codecHandle );
    ERRCHECK( result );

    Common_LoadFileMemory(Common_MediaPath("drumloop.wav"), &buff, &length);
    memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
    exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
    exinfo.length = length;

    result = system->createSound((const char *)buff, FMOD_OPENMEMORY | FMOD_LOOP_OFF, &exinfo, &sound1);
    ERRCHECK(result);

#2

Found the cause, the waveformatversion member of FMOD_CODEC_STATE must be set to FMOD_CODEC_WAVEFORMAT_VERSION in the codec open callback. The example code doesn’t do it.


#3

Hi Robert,
That is a bit of an oversight. Thanks for finding it i’ve added it to the example.
regards,