init
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
PROJECT(openvibe-plugins-dll-bridge)
|
||||
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION ${OV_GLOBAL_VERSION_STRING})
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.inl)
|
||||
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${PLUGINS_FOLDER}
|
||||
COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared")
|
||||
|
||||
# ---------------------------------
|
||||
INCLUDE("FindOpenViBE")
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEToolkit")
|
||||
INCLUDE("FindOpenViBEModuleEBML")
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
Example how to use a Fortran component to do signal processing
|
||||
|
||||
On Windows,
|
||||
|
||||
- Compile the Fortran code with a 32(!) bit fortran compiler.
|
||||
The Intel Fortran compiler has been observed to work. e.g.
|
||||
|
||||
> where ifort
|
||||
C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\ia32\ifort
|
||||
|
||||
> ifort /static /dll fortranbox_dll.f90
|
||||
|
||||
The resulting .dll file can be specified to the DLL Bridge box.
|
||||
Remember to set the full path correctly.
|
||||
|
||||
Using the /static flag allows you to distribute your built dll
|
||||
to other computers more easily.
|
||||
|
||||
|
||||
On Linux,
|
||||
|
||||
# gfortran -shared fortranbox_dll.f90 -o fortranbox_dll.so
|
||||
|
||||
Then specify the .so file to the DLL Bridge box.
|
||||
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
|
||||
!
|
||||
! This code illustrates passing a matrix in from OpenViBE, making modifications,
|
||||
! and sending another matrix back. Care must be taken that the difference in C/Fortran
|
||||
! row/column major order of the matrix storage is taken into account.
|
||||
!
|
||||
! This example adds the channel number to the channel data (so each channel will have noticable and different effect).
|
||||
! It also adds one channel with a constant pattern, to illustrate how to change the channel count. The
|
||||
! change of dimensions must be specified in the box_process_header() function.
|
||||
!
|
||||
|
||||
Module box
|
||||
|
||||
! Matrix dimensions in and out
|
||||
INTEGER g_rowsIn,g_colsIn, g_rowsOut,g_colsOut
|
||||
! Sampling rates in and out
|
||||
INTEGER g_samplingRateIn, g_samplingRateOut
|
||||
|
||||
CONTAINS
|
||||
|
||||
! this routine is run once at the beginning of playback. it can be used to precompute/load things needed later.
|
||||
! set errorCode to 0 on success, a non-zero code otherwise.
|
||||
subroutine box_init(inputParamsLength, inputParams, errorCode) bind(C)
|
||||
!DEC$ ATTRIBUTES DLLEXPORT :: box_init
|
||||
use,intrinsic:: iso_c_binding
|
||||
implicit none
|
||||
INTEGER(C_INT32_T), intent(in) :: inputParamsLength;
|
||||
CHARACTER(KIND=C_CHAR), dimension(inputParamsLength), intent(in) :: inputParams
|
||||
INTEGER(C_INT32_T), intent(out) :: errorCode;
|
||||
|
||||
! in this example, the routine does nothing much
|
||||
|
||||
write(*,*) "box_init() in Fortran"
|
||||
write(*,*) " Received params: ", inputParams
|
||||
|
||||
errorCode = 0
|
||||
end subroutine box_init
|
||||
|
||||
! this routine is run when OpenViBE receives a stream header. The purpose of this
|
||||
! function is to return the sizes of the output matrices, and change in the
|
||||
! sampling rate if any. If sampling rate is 0, the input of process()
|
||||
! will be just a matrix without a known sampling frequency.
|
||||
!
|
||||
! set errorCode to 0 on success, a non-zero code otherwise.
|
||||
subroutine box_process_header(rowsIn,colsIn,samplingRateIn,rowsOut,colsOut,samplingRateOut,errorCode) bind(C)
|
||||
!DEC$ ATTRIBUTES DLLEXPORT :: box_process_header
|
||||
use iso_c_binding
|
||||
INTEGER(C_INT32_T), intent(in) :: rowsIn, colsIn, samplingRateIn
|
||||
INTEGER(C_INT32_T), intent(out) :: rowsOut, colsOut, samplingRateOut
|
||||
INTEGER(C_INT32_T), intent(out) :: errorCode;
|
||||
|
||||
g_rowsIn = rowsIn
|
||||
g_colsIn = colsIn
|
||||
g_samplingRateIn = samplingRateIn
|
||||
|
||||
! Here rowOut=rowIn+1 since we want to add a channel in this example
|
||||
g_rowsOut = rowsIn + 1
|
||||
g_colsOut = colsIn
|
||||
g_samplingRateOut = samplingRateIn
|
||||
|
||||
write(*,*) " Process header: Dims", g_rowsIn, g_colsIn, "->", g_rowsOut, g_colsOut
|
||||
write(*,*) " Freq", g_SamplingRateIn, "->", g_samplingRateOut
|
||||
|
||||
rowsOut = g_rowsOut
|
||||
colsOut = g_colsOut
|
||||
|
||||
samplingRateOut = g_samplingRateOut
|
||||
|
||||
errorCode = 0;
|
||||
end subroutine box_process_header
|
||||
|
||||
! this routine is runs once for each matrix chunk of data.
|
||||
! set errorCode to 0 on success, a non-zero code otherwise.
|
||||
subroutine box_process(matIn,matOut,errorCode) bind(C)
|
||||
!DEC$ ATTRIBUTES DLLEXPORT :: box_process
|
||||
use iso_c_binding
|
||||
REAL(C_DOUBLE), intent(in) :: matIn(g_rowsIn*g_colsIn)
|
||||
REAL(C_DOUBLE), intent(out) :: matOut(g_rowsOut*g_colsOut)
|
||||
INTEGER(C_INT32_T), intent(out) :: errorCode
|
||||
REAL, DIMENSION(1:g_rowsIn,1:g_colsIn) :: A;
|
||||
REAL, DIMENSION(1:g_rowsOut,1:g_colsOut) :: B;
|
||||
! write(*,*) "box_process() in Fortran" , rows, " ", cols
|
||||
|
||||
! matrix from C/C++ is in row-major order, reshape
|
||||
A = reshape(matIn, (/ g_rowsIn, g_colsIn /), ORDER = (/ 2, 1 /) )
|
||||
|
||||
! Add +nChannel to each channel
|
||||
do i=1,g_rowsIn
|
||||
do j=1,g_colsIn
|
||||
B(i,j) = A(i,j) + i;
|
||||
end do
|
||||
end do
|
||||
|
||||
! the new channel just has a simple pattern
|
||||
do j=1,g_colsOut
|
||||
B(g_rowsOut,j) = j;
|
||||
end do
|
||||
|
||||
! print the matrix
|
||||
!WRITE(*,*)
|
||||
!DO I = LBOUND(B,1), UBOUND(B,1)
|
||||
! WRITE(*,*) (B(I,J), J = LBOUND(B,2), UBOUND(B,2))
|
||||
!END DO
|
||||
|
||||
matOut = reshape( TRANSPOSE(B), (/ g_rowsOut * g_colsOut /) )
|
||||
|
||||
errorCode = 0
|
||||
end subroutine box_process
|
||||
|
||||
! this routine is run once at the end of playback. it can be used to deallocate resources (memory, files, ...).
|
||||
! set errorCode to 0 on success, a non-zero code otherwise.
|
||||
subroutine box_uninit(errorCode) bind(C)
|
||||
!DEC$ ATTRIBUTES DLLEXPORT :: box_uninit
|
||||
use iso_c_binding
|
||||
INTEGER(C_INT32_T), intent(out) :: errorCode
|
||||
|
||||
! in this example, the routine does nothing much
|
||||
|
||||
write(*,*) "box_uninit() in Fortran"
|
||||
|
||||
errorCode = 0
|
||||
end subroutine box_uninit
|
||||
|
||||
end module box
|
||||
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
#include "ovpCBoxAlgorithmDLLBridge.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(TARGET_OS_Windows)
|
||||
#include <windows.h>
|
||||
#elif defined(TARGET_OS_Linux)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace DLLBridge {
|
||||
|
||||
// #define DLLBRIDGE_DEBUG
|
||||
#if defined(DLLBRIDGE_DEBUG)
|
||||
static void dumpMatrix(Kernel::ILogManager& mgr, const CMatrix& mat, const CString& desc)
|
||||
{
|
||||
mgr << Kernel::LogLevel_Info << desc << "\n";
|
||||
for (size_t i = 0; i < mat.getDimensionSize(0); i++)
|
||||
{
|
||||
mgr << Kernel::LogLevel_Info << "Row " << i << ": ";
|
||||
for (size_t j = 0; j < mat.getDimensionSize(1); j++) { mgr << mat.getBuffer()[i * mat.getDimensionSize(1) + j] << " "; }
|
||||
mgr << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_OS_Windows)
|
||||
#define OPEN_FUNC(file, library) \
|
||||
std::string tmp = file.toASCIIString();\
|
||||
std::replace(tmp.begin(), tmp.end(), '/', '\\');\
|
||||
file = tmp.c_str();\
|
||||
library = LoadLibrary(file.toASCIIString());
|
||||
|
||||
#define PROC_FUNC GetProcAddress
|
||||
#define ERR_FUNC GetLastError
|
||||
#define CLOSE_FUNC FreeLibrary
|
||||
#else
|
||||
#define OPEN_FUNC(file, library) library = dlopen(file.toASCIIString(), RTLD_LAZY);
|
||||
#define PROC_FUNC dlsym
|
||||
#define ERR_FUNC dlerror
|
||||
#define CLOSE_FUNC dlclose
|
||||
#endif
|
||||
|
||||
// This function is called once when user presses play in Designer
|
||||
bool CDLLBridge::initialize()
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Initializing\n";
|
||||
|
||||
m_encoder = nullptr;
|
||||
m_decoder = nullptr;
|
||||
m_library = nullptr;
|
||||
m_initialize = nullptr;
|
||||
m_processHeader = nullptr;
|
||||
m_process = nullptr;
|
||||
m_uninitialize = nullptr;
|
||||
|
||||
m_dllFile = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
m_parameters = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
||||
|
||||
if (m_dllFile == CString(""))
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Need a DLL file\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
OPEN_FUNC(m_dllFile, m_library)
|
||||
if (!m_library)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to load " << m_dllFile << ", error code " << int64_t(ERR_FUNC()) << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_initialize = INITFUNC(PROC_FUNC(m_library, "box_init"));
|
||||
if (!m_initialize)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Unable to find box_init() in the DLL\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_process = PROCESSFUNC(PROC_FUNC(m_library, "box_process"));
|
||||
if (!m_process)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Unable to find box_process() in the DLL\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_processHeader = PROCESSHEADERFUNC(PROC_FUNC(m_library, "box_process_header"));
|
||||
if (!m_processHeader)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Unable to find box_process_header() in the DLL\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_uninitialize = UNINITFUNC(PROC_FUNC(m_library, "box_uninit"));
|
||||
if (!m_uninitialize)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Unable to find box_uninit() in the DLL\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const Kernel::IBox& boxContext = this->getStaticBoxContext();
|
||||
boxContext.getInputType(0, m_inputTypeID);
|
||||
if (m_inputTypeID == OV_TypeId_StreamedMatrix)
|
||||
{
|
||||
Toolkit::TStreamedMatrixDecoder<CDLLBridge>* decoder = new Toolkit::TStreamedMatrixDecoder<CDLLBridge>;
|
||||
Toolkit::TStreamedMatrixEncoder<CDLLBridge>* encoder = new Toolkit::TStreamedMatrixEncoder<CDLLBridge>;
|
||||
|
||||
decoder->initialize(*this, 0);
|
||||
encoder->initialize(*this, 0);
|
||||
|
||||
m_decoder = decoder;
|
||||
m_encoder = encoder;
|
||||
}
|
||||
else if (m_inputTypeID == OV_TypeId_Signal)
|
||||
{
|
||||
Toolkit::TSignalDecoder<CDLLBridge>* decoder = new Toolkit::TSignalDecoder<CDLLBridge>;
|
||||
Toolkit::TSignalEncoder<CDLLBridge>* encoder = new Toolkit::TSignalEncoder<CDLLBridge>;
|
||||
|
||||
decoder->initialize(*this, 0);
|
||||
encoder->initialize(*this, 0);
|
||||
|
||||
m_decoder = decoder;
|
||||
m_encoder = encoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Unknown input type " << m_inputTypeID << ". This should never happen.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_init() : Calling\n";
|
||||
|
||||
// Do some initialization in DLL
|
||||
int length = m_parameters.length();
|
||||
int code = 0;
|
||||
m_initialize(&length, m_parameters.toASCIIString(), &code);
|
||||
if (code)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "DLL box_init() : Returned error code " << code << "\n";
|
||||
return false;
|
||||
}
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_init() : Return ok\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is called once when user presses Stop in Designer
|
||||
bool CDLLBridge::uninitialize()
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Uninitializing\n";
|
||||
|
||||
if (m_uninitialize)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_uninit() : Calling\n";
|
||||
|
||||
// Do some uninitialization in DLL
|
||||
int code = 0;
|
||||
m_uninitialize(&code);
|
||||
|
||||
if (code)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "DLL box_uninit() : Returned error code " << code << "\n";
|
||||
return false;
|
||||
}
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_uninit() : Return ok\n";
|
||||
}
|
||||
|
||||
if (m_encoder)
|
||||
{
|
||||
m_encoder->uninitialize();
|
||||
delete m_encoder;
|
||||
m_encoder = nullptr;
|
||||
}
|
||||
if (m_decoder)
|
||||
{
|
||||
m_decoder->uninitialize();
|
||||
delete m_decoder;
|
||||
m_decoder = nullptr;
|
||||
}
|
||||
|
||||
if (m_library)
|
||||
{
|
||||
CLOSE_FUNC(m_library);
|
||||
m_library = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDLLBridge::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is called for every signal chunk (matrix of N samples [channels x samples]).
|
||||
bool CDLLBridge::process()
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Process chunk\n";
|
||||
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
|
||||
for (uint32_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
||||
{
|
||||
// m_decoder/m_encoder should point to StreamedMatrix*coder or Signal*Coder by construction,
|
||||
// the latter appears to be static castable to the former, in practice.
|
||||
// n.b. dynamic cast does not work here runtime (this does, for the moment). I do not hazard
|
||||
// an explanation here. Anybody wanting to find out the reasons be prepared to digest the
|
||||
// codec template inheritance relationships in toolkit for a while.
|
||||
Toolkit::TStreamedMatrixDecoder<CDLLBridge>* decoder = dynamic_cast<Toolkit::TStreamedMatrixDecoder<CDLLBridge>*>(m_decoder);
|
||||
Toolkit::TStreamedMatrixEncoder<CDLLBridge>* encoder = dynamic_cast<Toolkit::TStreamedMatrixEncoder<CDLLBridge>*>(m_encoder);
|
||||
|
||||
decoder->decode(i);
|
||||
|
||||
if (decoder->isHeaderReceived())
|
||||
{
|
||||
if (decoder->getOutputMatrix()->getDimensionCount() != 2)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Only 2 dimensional matrices supported\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
int iSampling = 0;
|
||||
|
||||
if (m_inputTypeID == OV_TypeId_Signal)
|
||||
{
|
||||
Toolkit::TSignalDecoder<CDLLBridge>* signalDecoder = dynamic_cast<Toolkit::TSignalDecoder<CDLLBridge>*>(m_decoder);
|
||||
iSampling = int(signalDecoder->getOutputSamplingRate());
|
||||
}
|
||||
|
||||
int iNRows = decoder->getOutputMatrix()->getDimensionSize(0);
|
||||
int iNCols = decoder->getOutputMatrix()->getDimensionSize(1);
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_process_header() : Calling\n";
|
||||
|
||||
int code = 0, oNRows = 0, oNCols = 0, oSampling = 0;
|
||||
m_processHeader(&iNRows, &iNCols, &iSampling, &oNRows, &oNCols, &oSampling, &code);
|
||||
if (code)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "DLL box_process_header() : Returned error code " << code << "\n";
|
||||
return false;
|
||||
}
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_process_header() : Return ok\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "The function declared" << " rowsOut=" << oNRows << " colsOut=" << oNCols << " sRateOut=" << oSampling << "\n";
|
||||
|
||||
encoder->getInputMatrix()->resize(oNRows, oNCols);
|
||||
|
||||
if (m_inputTypeID == OV_TypeId_Signal)
|
||||
{
|
||||
Toolkit::TSignalEncoder<CDLLBridge>* signalEncoder = dynamic_cast<Toolkit::TSignalEncoder<CDLLBridge>*>(m_encoder);
|
||||
|
||||
signalEncoder->getInputSamplingRate() = oSampling;
|
||||
}
|
||||
|
||||
encoder->encodeHeader();
|
||||
|
||||
boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
|
||||
}
|
||||
|
||||
if (decoder->isBufferReceived())
|
||||
{
|
||||
double* input = decoder->getOutputMatrix()->getBuffer();
|
||||
double* output = encoder->getInputMatrix()->getBuffer();
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_process() : Calling\n";
|
||||
|
||||
// Process the sample chunk in DLL
|
||||
int errorCode = 0;
|
||||
m_process(input, output, &errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "DLL box_process() : Returned error code " << errorCode << "\n";
|
||||
return false;
|
||||
}
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "DLL box_process() : Return ok\n";
|
||||
|
||||
encoder->encodeBuffer();
|
||||
boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
|
||||
}
|
||||
if (decoder->isEndReceived())
|
||||
{
|
||||
encoder->encodeEnd();
|
||||
boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace DLLBridge
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
#if defined(TARGET_OS_Windows)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace DLLBridge {
|
||||
class CDLLBridge final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { delete this; }
|
||||
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
|
||||
bool processInput(const size_t index) override;
|
||||
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_DLLBridge)
|
||||
|
||||
private:
|
||||
|
||||
Toolkit::TDecoder<CDLLBridge>* m_decoder = nullptr;
|
||||
Toolkit::TEncoder<CDLLBridge>* m_encoder = nullptr;
|
||||
|
||||
CIdentifier m_inputTypeID = CIdentifier::undefined();
|
||||
CString m_dllFile;
|
||||
CString m_parameters;
|
||||
|
||||
// These functions are expected from the DLL library
|
||||
// @note the inputs are non-const on purpose to ensure maximum compatibility with non-C++ dlls
|
||||
typedef void (* INITFUNC)(int* paramsLength, const char* params, int* errorCode);
|
||||
typedef void (* UNINITFUNC)(int* errorCode);
|
||||
typedef void (* PROCESSHEADERFUNC)(int* rowsIn, int* colsIn, int* samplingRateIn, int* rowsOut, int* colsOut, int* samplingRateOut,
|
||||
int* errorCode);
|
||||
typedef void (* PROCESSFUNC)(double* matIn, double* matOut, int* errorCode);
|
||||
|
||||
INITFUNC m_initialize = nullptr;
|
||||
UNINITFUNC m_uninitialize = nullptr;
|
||||
PROCESSHEADERFUNC m_processHeader = nullptr;
|
||||
PROCESSFUNC m_process = nullptr;
|
||||
|
||||
#if defined(TARGET_OS_Windows)
|
||||
HINSTANCE m_library = nullptr;
|
||||
#elif defined(TARGET_OS_Linux)
|
||||
void* m_library = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
class CDLLBridgeListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getInputType(index, typeID);
|
||||
box.setOutputType(0, typeID);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onOutputTypeChanged(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getOutputType(index, typeID);
|
||||
box.setInputType(0, typeID);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
/**
|
||||
* Plugin's description
|
||||
*/
|
||||
class CDLLBridgeDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
CString getName() const override { return CString("DLL Bridge"); }
|
||||
CString getAuthorName() const override { return CString("Jussi T. Lindgren"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Inria"); }
|
||||
CString getShortDescription() const override { return CString("Process a signal or matrix stream with a DLL"); }
|
||||
CString getDetailedDescription() const override { return CString(""); }
|
||||
CString getCategory() const override { return CString("Scripting"); }
|
||||
CString getVersion() const override { return CString("0.2"); }
|
||||
CString getStockItemName() const override { return CString("gtk-convert"); }
|
||||
void release() override { }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_DLLBridge; }
|
||||
IPluginObject* create() override { return new CDLLBridge(); }
|
||||
IBoxListener* createBoxListener() const override { return new CDLLBridgeListener; }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addSetting("DLL file", OV_TypeId_Filename, "");
|
||||
prototype.addSetting("Parameters", OV_TypeId_String, "");
|
||||
|
||||
prototype.addInput("Input",OV_TypeId_Signal);
|
||||
prototype.addOutput("Output",OV_TypeId_Signal);
|
||||
|
||||
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
|
||||
prototype.addInputSupport(OV_TypeId_Signal);
|
||||
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
|
||||
prototype.addOutputSupport(OV_TypeId_Signal);
|
||||
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
|
||||
|
||||
prototype.addFlag(OV_AttributeId_Box_FlagIsUnstable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_DLLBridgeDesc)
|
||||
};
|
||||
} // namespace DLLBridge
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// Boxes
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVP_ClassId_DLLBridge OpenViBE::CIdentifier(0x6F837408, 0x35BA0312)
|
||||
#define OVP_ClassId_DLLBridgeDesc OpenViBE::CIdentifier(0x2BB7368F, 0x207D6485)
|
||||
|
||||
// Global defines
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OV_AttributeId_Box_FlagIsUnstable OpenViBE::CIdentifier(0x666FFFFF, 0x666FFFFF)
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#include "ovp_defines.h"
|
||||
|
||||
#include "box-algorithms/ovpCBoxAlgorithmDLLBridge.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace DLLBridge {
|
||||
|
||||
OVP_Declare_Begin()
|
||||
context.getTypeManager().registerEnumerationEntry(OV_TypeId_BoxAlgorithmFlag, OV_AttributeId_Box_FlagIsUnstable.toString(),
|
||||
OV_AttributeId_Box_FlagIsUnstable.id());
|
||||
|
||||
OVP_Declare_New(CDLLBridgeDesc);
|
||||
OVP_Declare_End()
|
||||
|
||||
} // namespace DLLBridge
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
Reference in New Issue
Block a user