DXi2 SDK Errata Page


The following is a list of errors in the DXi SDK, and how to correct them.  This page will be updated as necessary.  You can be informed of new releases of the DXi2 SDK by filling out the simple Development Kit Update Notification form.

Note: To determine which version of the SDK you have installed, go to the Windows Control Panel, Add/Remove programs, click on "Cakewalk DXi 2 SDK", and then click on the support information link.

Errata

1. Host Application crashes in KERNEL32 on shutdown (Win9x, ME)

SDK Version
2.0.0.0

Cause
The Win32 DeleteCriticalSection API was being called multiple times by the termination code.

Solution
Change DXi2 SDK\HostApp\DXiPlayer.cpp:

Move the code at line 144 ...

    DeleteCriticalSection( &m_csData );

... to line 56, making it the last step of the CDXiPlayer destructor.

2. Host Application leaving an invisible process running upon exit

SDK Version
2.0.0.0

Cause
A COM reference count leak in the code to obtain input and output pins from the patched DXi.

Solution
Change DXi2 SDK\HostApp\DXiClasses\DxFilterGraph.cpp:

(1) Replace the code at line 160 ...

    if (count == nOutPin)
        return pIPin;

... with this code:

    if (count == nOutPin)
    {
        pIEnumPins->Release();
        pIPin->Release();
        return pIPin;
    }

(2) Replace the code at line 201 ...

    if (PINDIR_INPUT == PinInfo.dir)
        return pIPin;


with this code ...

    if (PINDIR_INPUT == PinInfo.dir)
    {
        pIEnumPins->Release();
        pIPin->Release();
        return pIPin;
    }

3. Plug-ins created with the DXi 2 Wizard (MFC) do not unload

SDK Version
2.0.0.0

Cause
The AFX_MANAGE_STATE macro was missing in a required locations.

Solution
Change Filter.cpp, in your plug-in project.

(1) Add a call to AFX_MANAGE_STATE as the first line of the CFilter constructor:

    CFilter::CFilter( TCHAR* pName, LPUNKNOWN pUnk, HRESULT* phr ) :
    ...
    {
         AFX_MANAGE_STATE( AfxGetStaticModuleState() );
        ...
    }

(2) Add a call to AFX_MANAGE_STATE as the first line of the CFilter destructor:

    CFilter::~CFilter()
    {
         AFX_MANAGE_STATE( AfxGetStaticModuleState() );
        ...
    }

4. .NET compiler errors with NonMFC template projects

SDK Version
2.0.0.0

Cause
Missing casts when converting from floating point to integer data types.

Solution
These errors have been fixed in the 2.0.1.0 SDK.  Please download for a fix.

5. Compiler errors when using STLPORT library

SDK Version
2.0.0.0

Cause
STLPORT requires some custom configuration if it is to work with the free .NET compiler outside of visual studio.  Also. the STLPORT mulitset type is not compatible with the DXi SDK's use of multiset.

Solution
To allow STLPORT to recognize the free .NET compiler, please add the following lines to the end of stl_user_config.h

# define _STLP_NO_NEW_C_HEADERS 1

# define _STLP_NO_NEW_NEW_HEADER 1

# define _STLP_NO_BAD_ALLOC 1

# define _STLP_NO_EXCEPTION_HEADER 1

# define _STLP_USE_NO_IOSTREAMS 1

# undef _STLP_DEBUG

# undef _STLP_DEBUG_ALLOC

To fix the problem with the STLPORT multiset, you may do one of two things.  First, you can download the 2.0.1.0 DXi SDK.  Second, edit SoftSynth.h and SoftSynth.cpp, using a vector<DXiEvent> instead of multiset<DXiEvent> as the data type for m_qPending.

6. Memory Leak in Sample Host Application

SDK Version
2.0.0.0

Cause
After destroying the filter graph, the memory allocator needs to be told to
reset its properties, specifically the number of media samples it will
allocate.  Not doing this causes the number of media samples to increase
each time a new DXi is selected.

Solution
Add the following line of code to DXiClasses/DxFilterGraph.cpp.

CFilterGraph::DestroyGraph()
{
      ...
      CHECK( m_pMemAllocator->FreeAll() );
      CHECK( m_pMemAllocator->ResetProperties( 0 ) ); // NEW NEW

      return hr;
}

7. GetPersistSize Returns The Wrong Value

SDK Version
2.0.0.0

Cause
A misplaced semicolon in the wizard-generated code.

Solution
Remove the semicolon after "sizeof(DWORD)" in the implentation of PersistGetSize, located in <project>/<project>.cpp:

int C$$Safe_root$$::PersistGetSize() const
{
      int const cb
            = sizeof(DWORD)
            + NUM_PARAMS * (sizeof(DWORD) + sizeof(float));
      return cb;
}

8. Static Objects Are Not Constructed In Non-MFC Plug-Ins

SDK Version
2.0.0.0

Cause
Non-MFC projects were being configured to use DirectShow's DllEntryPoint function as the entry point for the DLL.  This is incorrect, because it prevents the C-runtime initialization code from being run.

Solution
(1) Add the following lines of code to PlugInApp.cpp, in your project directory:

extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL WINAPI
DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pv)
{
      return DllEntryPoint( hInstance, ulReason, pv );
}

(2) Go to Project | Settings, choose settings for All Configurations, click on the [Link] tab, and select the Output category.  Clear the contents of the Entry-point symbol field.

9. MFC-based Property Pages Do Not Appear In Cubase

SDK Version
2.0.0.0

Cause
Cubase attempts to get the size of property page before first setting its property page site.  This behavior causes the MFC COlePropertyPage base class to report an incorrect size for the property page.

Solution
Add the following lines of code to the NonDelegatingQueryInterface method of xxxPropPage.cpp, in your project directory:

STDMETHODIMP ...PropPage::NonDelegatingQueryInterface(...)
{
      AFX_MANAGE_STATE( AfxGetStaticModuleState() );
      ...
      if (S_OK == hr && m_bFirstQI)
      {
            // Work around interaction with Cubase, which asks
            // for the dialog's size before setting its site
            OnSetPageSite();
            ...
      }
      return hr;
}


10. Parameter Changes Aren't Applied In Sound Forge

SDK Version
2.0.0.0

Cause
Sound Forge will only apply parameter changes if the property page's "modified flag" has been set.  The sample code is missing call(s) to set this flag where needed.

Solution
Call COlePropertyPage::SetModifiedFlag whenever a parameter had been changed.  For example, in the AutoClip sample, you would need to add this call in 2 places:

void CAutoClipPropPage::OnEnabled()
        
{
            SetModifiedFlag( TRUE );
            ...
      }

      void CAutoClipPropPage::OnHScroll(...)
      {
            SetModifiedFlag( TRUE );
            ...
      }

11. Plug-Ins Do Not Appear In Certain Host Applications

SDK Version
2.0.0.0

Cause
The major media type for plug-in setup data should be MEDIATYPE_Audio, not MEDIATYPE_NULL.  Also, the filter object needs to implement a GetSetupData method.

Solution
In Filter.cpp, change the following lines of code.  The Major CLSID for sudPinTypes is changed to MEDIATYPE_Audio, the declarations of all setup data objects are changed from const to static, and GetSetupData is added.

static AMOVIESETUP_MEDIATYPE sudPinTypes =
{
    &MEDIATYPE_Audio,        // Major CLSID
    &MEDIASUBTYPE_NULL       // Minor type
};

static AMOVIESETUP_PIN psudPins[] =
{
   ...
};

static AMOVIESETUP_FILTER sudFilter =
{
   ...
};

LPAMOVIESETUP_FILTER CFilter::GetSetupData()
{
   return &sudFilter;
}

In Filter.h, add the following line of code.

class CFilter ...
{
public:
   ...
   LPAMOVIESETUP_FILTER GetSetupData();
};

 

12. Automation Rendering Can "Drop Out" During Looped Playback

SDK Version
2.0.0.0

Cause
Logic to flush "stale" envelopes in CParamEnvelope::UpdateValuesForRefTime was incorrect, leading to lost automation during looping playback.  This logic belongs in CParamEnvelope::AddEnvelope.

Solution
Remove the following lines in ParamEnvelope.cpp:

HRESULT CParamEnvelope::UpdateValuesForRefTime( ... )
{
   ...
   if (ix > 0)
      m_envSegs.erase( m_envSegs.begin(), m_envSegs.begin() + ix );

Add the following lines in ParamEnvelope.cpp:

HRESULT CParamEnvelope::AddEnvelope( ... )
          {
             ...
             // Add each segment, noting which one is earliest
         REFERENCE_TIME rtMin = _I64_MAX;
             for (DWORD ix = 0; ix < cSegments; ix++)
             {
            ...
                if (mpes.rtStart < rtMin)
                   rtMin = mpes.rtStart;
             }

         // Flush all segments prior to the first newly added one
             ix = IndexForRefTime( rtMin );
             if (ix > 0)
                m_envSegs.erase( m_envSegs.begin(), m_envSegs.begin()+ix );

         ...
      }


13. Pitch Wheel events are read incorrectly from SMFs

SDK Version
2.0.0.0, 2.0.1.0

Cause
Pitch wheel data was being treated as a unsigned value instead of a signed value, when converted into the MfxEvent format.

Solution
Add the following line in HostApp/SMF.cpp:

case WHEEL:       // WHEEL <wheellsb> <wheelmsb>

{
     
...
     
nWheel -= 8192;   // BUG FIX
      event.SetWheel( nWheel );
      pTrk->push_back( event );
      break;
}

 

14. Stream sample position does not update if no automation exists

SDK Version
2.0.0.0, 2.0.1.0

Cause
Logic to update the stream sample position assumed that automation data was present, and would get handled by a 'for' loop.

Solution
Change the following line in Filter.cpp

HRESULT CFilterInputPin::Receive( IMediaSample* pms )

{
     
...
     
HRESULT hrProcess = S_OK;
     
LONGLONG llPrevPos = m_pFilter->m_llSamplePosition;
     
LONGLONG llCurrPos = llPrevPos;     // BUG FIX
     
...

}

 

15. Enumerated parameter values are parsed incorrectly

SDK Version
2.0.0.0, 2.0.1.0

Cause
Due to a typopgraphical error, an '=' was used where '==' was required.

Solution
Change the following line in MediaParams.cpp:

HRESULT CMediaParams::GetParamText(...)

{
     
...
      if (*pwsz == L',')      // BUG FIX
      ...
}

 

16. Live MIDI input timestamps are incorrect for soft synths

SDK Version
2.0.0.0, 2.0.1.0

Cause
When converting an OnInput event's tick time to samples, the DXi code would always position the all events at the start of the buffer (by subtracting off the first event's time from all events).  This winds up moving the position of time-stamped input events, like those generated by Cakewalk's Arpeggiator MFX.  The fix is to convert ticks to sample directly from the input event's time, without repositioning.

Solution
Change the following lines in SoftSynth.cpp:

STDMETHODIMP CSoftSynth::OnInput( ... )

{
     
CAutoLock lock( m_pDXi );

      if (NULL == pqIn)
           
return E_POINTER;
     
if (NULL == m_pTempoMap)
            return E_UNEXPECTED;
 

      long  lTimeFirst = 0;   // BUG FIX: remove this line
      int   nCount = 0;

      HRESULT hr = pqIn->GetCount( &nCount );

      if (FAILED( hr ))
            return hr;

        for (int ix = 0; ix < nCount; ++ix)
     {

            // Get the next datum
           
MfxData md;
           
hr = pqIn->GetAt( ix, &md );
           
if (FAILED( hr ))
                 
break;

            // BUG FIX: remove these lines

            // Determine the offset of the first event

            if (0 == ix)

lTimeFirst = md.m_lTime;

            // Determine offset in samples of this event

            LONGLONG llSampOffset =

TicksToSamples( md.m_lTime ); // BUG FIX

      ...

}


17. Automation can lock up host app and not be rendered correctly

SDK Version
2.0.0.0, 2.0.1.0

Cause
A variable that should have been signed was declared as unsigned, and then allowing -1 (interpreted as ULONG_MAX due to unsigned) to access an out of bounds array element.  Also, if the host pre-rolls automation by a long amount, envelopes can be flushed prematurely.

Solution
Declare loop variable 'ix' as an int instead of a DWORD.  Keep track of the latest time actually rendered, and make sure we never auto-flush envelopes before that time.

Change the following lines in ParamEnvelope.cpp:

CParamEnvelope::CParamEnvelope() :

      ...

      m_bValidDeltas( TRUE ),
     
m_rtRendered( 0 )

{

}

HRESULT CParamEnvelope::UpdateValuesForRefTime( ... )

{
      ...

      // Keep track of the latest time rendered so far
     
m_rtRendered = max( m_rtRendered, rt );

      return S_OK;
}


HRESULT CParamEnvelope::AddEnvelope( ... )

{
     
...
     
for (int ix = 0; ix < cSegments; ix++) // BUG FIX

      {
           
...
      }
 

      // Flush all segments prior to the first newly added one

      ix = IndexForRefTime( rtMin );
     
if (ix > 0 && rtMin < m_rtRendered) // BUG FIX
      ...
}

 

HRESULT CParamEnvelope::FlushEnvelope( ... )

{
     
...  

      // Once envelopes get thrown away, we need to redetermine
      // our max render time

     
m_rtRendered = 0; // BUG FIX
      cleanup();  

      return S_OK;
}

Add the following line to ParamEnvelope.h:

class CParamEnvelope : public CCritSec

{
     
...
private:  

      float             m_fOverrideValue;
     
REFERENCE_TIME    m_rtRendered; // BUG FIX

};