<commit_before>#include "gtest/gtest.h"
#include "Pkcstest.hpp"
#include <Cryptoki.h>
#include <CryptokiException.h>

using namespace objck;
class Cryptoki_Test : public ::testing::Test {

protected :

	static CK_LAMBDA_FUNCTION_LIST* pkcs11;

	static void SetUpTestCase() {
		pkcs11 = pkcstest::getMocker();
	}

	static void TearDownTestCase() {}

	void SetUp()
	{
		pkcstest::setUpMockerFunctions(pkcs11);
	}
};

CK_LAMBDA_FUNCTION_LIST* Cryptoki_Test::pkcs11 = NULL;

TEST_F(Cryptoki_Test, Finalize_should_be_called_on_destructor) {
	bool called = false;
	pkcs11->C_Finalize = [&](void* ptr) -> CK_RV {
		called = true;
		return CKR_OK;
	};

	{Cryptoki p11module("/tmp/pkcs11mocked.so");}
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, Initialize_OK)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	bool called = false;
	pkcs11->C_Initialize = [&](void* ptr) -> CK_RV {
		called = true;
		return CKR_OK;
	};

	EXPECT_NO_THROW(p11module.initialize());
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, Initialize_Failed_causes_exception)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	pkcs11->C_Initialize = [&](void* ptr) {
		return CKR_GENERAL_ERROR;
	};

	try {
		p11module.initialize();
		EXPECT_TRUE(false);
	} catch (CryptokiException& e) {
		EXPECT_EQ(e.getErrorCode(), CKR_GENERAL_ERROR);
	}
}

TEST_F(Cryptoki_Test, getInfo)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	pkcs11->C_GetInfo = [&](CK_INFO *info) -> CK_RV {
		info->cryptokiVersion.major = 6;
		info->cryptokiVersion.minor = 7;
		info->flags = 0;
		info->libraryVersion.major = 12;
		info->libraryVersion.minor = 13;

		return CKR_OK;
	};

	Info info;
	info = p11module.getInfo();

	ASSERT_EQ(info.majorVersion(),6);
	ASSERT_EQ(info.minorVersion(),7);
	ASSERT_EQ(info.flags(), Info::EMPTY);
	ASSERT_EQ(info.libraryMajorVersion(),12);
	ASSERT_EQ(info.libraryMinorVersion(),13);
}

TEST_F(Cryptoki_Test, getInfo_error)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	pkcs11->C_GetInfo = [&](CK_INFO *info) -> CK_RV {

		return CKR_GENERAL_ERROR;
	};

	try {
		p11module.getInfo();
		EXPECT_TRUE(false);
	} catch (CryptokiException& e) {
		EXPECT_EQ(e.getErrorCode(), CKR_GENERAL_ERROR);
	}
}

TEST_F(Cryptoki_Test, getFunctionList)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

  	bool called = false;
	pkcs11->C_Initialize = [&](void* ptr) -> CK_RV {
		EXPECT_EQ(ptr, (void*)0x123456);
		called = true;
		return CKR_OK;
	};

	FunctionList test = p11module.getFunctionList();

	EXPECT_NO_THROW({
		CK_RV rv = (*test.C_Initialize)((void*)0x123456);
		EXPECT_EQ(rv, CKR_OK);
	});
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, initToken) {
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	bool called = false;
	std::string pin = "123456";
	std::string label = "test";

	pkcs11->C_InitToken = [&](CK_SLOT_ID slot_id, unsigned char *pin,
		unsigned long pin_len, unsigned char *label) -> CK_RV {
		called = true;
		//TODO(perin): compare strings?
		return CKR_OK;
	};

	EXPECT_NO_THROW(p11module.initToken(0, pin, label));
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, initToken_Failed_causes_exception) {
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	bool called = false;

	pkcs11->C_InitToken = [&](CK_SLOT_ID slot_id, unsigned char *pin,
		unsigned long pin_len, unsigned char *label) -> CK_RV {
		called = true;
		return CKR_GENERAL_ERROR;
	};

	std::string pin = "123456";
	std::string label = "test";
	try {
		p11module.initToken(0, pin, label);
		EXPECT_TRUE(false);
	} catch (CryptokiException& e) {
		EXPECT_EQ(e.getErrorCode(), CKR_GENERAL_ERROR);
	}
	EXPECT_TRUE(called);
}
<commit_msg>Adding missing tests for Info<commit_after>#include "gtest/gtest.h"
#include "Pkcstest.hpp"
#include <Cryptoki.h>
#include <CryptokiException.h>

using namespace objck;
class Cryptoki_Test : public ::testing::Test {

protected :

	static CK_LAMBDA_FUNCTION_LIST* pkcs11;

	static void SetUpTestCase() {
		pkcs11 = pkcstest::getMocker();
	}

	static void TearDownTestCase() {}

	void SetUp()
	{
		pkcstest::setUpMockerFunctions(pkcs11);
	}
};

CK_LAMBDA_FUNCTION_LIST* Cryptoki_Test::pkcs11 = NULL;

TEST_F(Cryptoki_Test, Finalize_should_be_called_on_destructor) {
	bool called = false;
	pkcs11->C_Finalize = [&](void* ptr) -> CK_RV {
		called = true;
		return CKR_OK;
	};

	{Cryptoki p11module("/tmp/pkcs11mocked.so");}
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, Initialize_OK)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	bool called = false;
	pkcs11->C_Initialize = [&](void* ptr) -> CK_RV {
		called = true;
		return CKR_OK;
	};

	EXPECT_NO_THROW(p11module.initialize());
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, Initialize_Failed_causes_exception)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	pkcs11->C_Initialize = [&](void* ptr) {
		return CKR_GENERAL_ERROR;
	};

	try {
		p11module.initialize();
		EXPECT_TRUE(false);
	} catch (CryptokiException& e) {
		EXPECT_EQ(e.getErrorCode(), CKR_GENERAL_ERROR);
	}
}

TEST_F(Cryptoki_Test, getInfo)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	pkcs11->C_GetInfo = [&](CK_INFO *info) -> CK_RV {
		info->cryptokiVersion.major = 6;
		info->cryptokiVersion.minor = 7;
		info->flags = 0;
		info->libraryVersion.major = 12;
		info->libraryVersion.minor = 13;
		memcpy(info->manufacturerID, "Perinovsky                      ", 32);
		memcpy(info->libraryDescription, "Claud Computing                 ", 32);
		return CKR_OK;
	};

	Info info;
	info = p11module.getInfo();

	ASSERT_EQ(info.majorVersion(),6);
	ASSERT_EQ(info.minorVersion(),7);
	ASSERT_EQ(info.version(),"6.7");
	ASSERT_EQ(info.manufacturerId(), "Perinovsky                      ");
	ASSERT_EQ(info.libraryDescription(), "Claud Computing                 ");
	ASSERT_EQ(info.flags(), Info::EMPTY);
	ASSERT_EQ(info.libraryMajorVersion(),12);
	ASSERT_EQ(info.libraryMinorVersion(),13);
	ASSERT_EQ(info.libraryVersion(),"12.13");

	CK_INFO recoveredStruct = info.getInfo();
	ASSERT_EQ(recoveredStruct.cryptokiVersion.major, 6);
	ASSERT_EQ(recoveredStruct.cryptokiVersion.minor, 7);
	ASSERT_EQ(recoveredStruct.flags, 0);
	ASSERT_EQ(recoveredStruct.libraryVersion.major, 12);
	ASSERT_EQ(recoveredStruct.libraryVersion.minor, 13);
	ASSERT_FALSE(memcmp(recoveredStruct.manufacturerID, "Perinovsky                      ", 32));
	ASSERT_FALSE(memcmp(recoveredStruct.libraryDescription, "Claud Computing                 ", 32));
}

TEST_F(Cryptoki_Test, getInfo_error)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	pkcs11->C_GetInfo = [&](CK_INFO *info) -> CK_RV {

		return CKR_GENERAL_ERROR;
	};

	try {
		p11module.getInfo();
		EXPECT_TRUE(false);
	} catch (CryptokiException& e) {
		EXPECT_EQ(e.getErrorCode(), CKR_GENERAL_ERROR);
	}
}

TEST_F(Cryptoki_Test, getFunctionList)
{
	Cryptoki p11module("/tmp/pkcs11mocked.so");

  	bool called = false;
	pkcs11->C_Initialize = [&](void* ptr) -> CK_RV {
		EXPECT_EQ(ptr, (void*)0x123456);
		called = true;
		return CKR_OK;
	};

	FunctionList test = p11module.getFunctionList();

	EXPECT_NO_THROW({
		CK_RV rv = (*test.C_Initialize)((void*)0x123456);
		EXPECT_EQ(rv, CKR_OK);
	});
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, initToken) {
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	bool called = false;
	std::string pin = "123456";
	std::string label = "test";

	pkcs11->C_InitToken = [&](CK_SLOT_ID slot_id, unsigned char *pin,
		unsigned long pin_len, unsigned char *label) -> CK_RV {
		called = true;
		//TODO(perin): compare strings?
		return CKR_OK;
	};

	EXPECT_NO_THROW(p11module.initToken(0, pin, label));
	EXPECT_TRUE(called);
}

TEST_F(Cryptoki_Test, initToken_Failed_causes_exception) {
	Cryptoki p11module("/tmp/pkcs11mocked.so");

	bool called = false;

	pkcs11->C_InitToken = [&](CK_SLOT_ID slot_id, unsigned char *pin,
		unsigned long pin_len, unsigned char *label) -> CK_RV {
		called = true;
		return CKR_GENERAL_ERROR;
	};

	std::string pin = "123456";
	std::string label = "test";
	try {
		p11module.initToken(0, pin, label);
		EXPECT_TRUE(false);
	} catch (CryptokiException& e) {
		EXPECT_EQ(e.getErrorCode(), CKR_GENERAL_ERROR);
	}
	EXPECT_TRUE(called);
}
<|endoftext|>


<commit_before>/****************************************************************************
*
* NAME: smbPitchShift.cpp
* VERSION: 1.2
* HOME URL: http://blogs.zynaptiq.com/bernsee
* KNOWN BUGS: none
*
* SYNOPSIS: Routine for doing pitch shifting while maintaining
* duration using the Short Time Fourier Transform.
*
* DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
* (one octave down) and 2. (one octave up). A value of exactly 1 does not change
* the pitch. numSampsToProcess tells the routine how many samples in indata[0...
* numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
* numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
* data in-place). fftFrameSize defines the FFT frame size used for the
* processing. Typical values are 1024, 2048 and 4096. It MUST be a power of 2.
* oversamp is the STFT oversampling factor which also determines the overlap
* between adjacent STFT frames. It should at least be 4 for moderate scaling
* ratios. A value of 32 is recommended for best quality. sampleRate takes the
* sample rate for the signal in unit Hz, ie. 44100 for 44.1 kHz audio. The data
* passed to the routine in indata[] should be in the range [-1.0, 1.0), which is
* also the output range for the data, make sure you scale the data accordingly
* (for 16bit signed integers you would have to divide (and multiply) by 32768).
*
* COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
*
* 						The Wide Open License (WOL)
*
* Permission to use, copy, modify, distribute and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice and this license appear in all source copies.
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*
*****************************************************************************/

#ifndef SMBPITCHSHIFT_HPP
#define SMBPITCHSHIFT_HPP

#include <algorithm>
#include <cmath>
#include <cstdint>

namespace smb
{
    namespace
    {
        constexpr float pi = 3.14159265358979323846F;

        // Use own implementation because std::complex has a poor performance
        template <class T>
        struct Complex final
        {
            constexpr Complex<T> operator+(const Complex& other) const noexcept
            {
                return Complex{real + other.real, imag + other.imag};
            }

            constexpr Complex<T>& operator+=(const Complex& other)
            {
                real += other.real;
                imag += other.imag;
                return *this;
            }

            constexpr Complex<T> operator-(const Complex& other) const noexcept
            {
                return Complex{real - other.real, imag - other.imag};
            }

            constexpr Complex<T> operator-() const noexcept
            {
                return Complex{-real, -imag};
            }

            constexpr Complex<T>& operator-=(const Complex& other) noexcept
            {
                real -= other.real;
                imag -= other.imag;
                return *this;
            }

            constexpr Complex<T> operator*(const Complex& other) const noexcept
            {
                return Complex{real * other.real - imag * other.imag, real * other.imag + imag * other.real};
            }

            constexpr Complex<T>& operator*=(const Complex& other) noexcept
            {
                float tempReal = real;
                real = tempReal * other.real - imag * other.imag;
                imag = tempReal * other.imag + imag * other.real;
                return *this;
            }

            inline T magnitude() const noexcept
            {
                return sqrt(real * real + imag * imag);
            }

            T real;
            T imag;
        };

        template <int32_t sign, uint32_t fftFrameSize>
        void fft(Complex<float>* fftBuffer) noexcept
        {
            // Bit-reversal permutation applied to a sequence of fftFrameSize items
            for (uint32_t i = 1; i < fftFrameSize - 1; ++i)
            {
                uint32_t j = 0;

                for (uint32_t bitm = 1; bitm < fftFrameSize; bitm <<= 1)
                {
                    if (i & bitm) ++j;
                    j <<= 1;
                }
                j >>= 1;

                if (i < j)
                    std::swap(fftBuffer[i], fftBuffer[j]);
            }

            // Iterative form of Danielson-Lanczos lemma
            uint32_t step = 2;
            for (uint32_t i = 1; i < fftFrameSize; i <<= 1, step <<= 1)
            {
                const uint32_t step2 = step >> 1;
                const float arg = pi / step2;

                const Complex<float> w{std::cos(arg), std::sin(arg) * sign};
                Complex<float> u{1.0F, 0.0F};
                for (uint32_t j = 0; j < step2; ++j)
                {
                    for (uint32_t k = j; k < fftFrameSize; k += step)
                    {
                        const Complex<float> temp = fftBuffer[k + step2] * u;
                        fftBuffer[k + step2] = fftBuffer[k] - temp;
                        fftBuffer[k] += temp;
                    }

                    u *= w;
                }
            }
        }
    }

    template <uint32_t fftFrameSize, uint32_t oversamp>
    class PitchShift final
    {
    public:
        PitchShift()
        {
            // Hann window
            for (uint32_t k = 0; k < fftFrameSize; ++k)
                window[k] = 0.5F * (1.0F + std::cos(2.0F * pi * static_cast<float>(k) / static_cast<float>(fftFrameSize)));
        }

        /*
            Routine process(). See top of file for explanation
            Purpose: doing pitch shifting while maintaining duration using the Short
            Time Fourier Transform.
            Author: (c)1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
        */
        void process(const float pitchShift, const uint32_t numSampsToProcess,
                     const uint32_t sampleRate, const float* indata, float* outdata) noexcept
        {
            // set up some handy variables
            const uint32_t fftFrameSizeHalf = fftFrameSize / 2;
            const uint32_t stepSize = fftFrameSize / oversamp;
            const float freqPerBin = static_cast<float>(sampleRate) / static_cast<float>(fftFrameSize);
            const float expected = 2.0F * pi * static_cast<float>(stepSize) / static_cast<float>(fftFrameSize);
            const uint32_t inFifoLatency = fftFrameSize - stepSize;
            if (rover == 0) rover = inFifoLatency;

            // main processing loop
            for (uint32_t i = 0; i < numSampsToProcess; ++i)
            {
                // As long as we have not yet collected enough data just read in
                inFifo[rover] = indata[i];
                outdata[i] = outFifo[rover - inFifoLatency];
                ++rover;

                // now we have enough data for processing
                if (rover >= fftFrameSize)
                {
                    rover = inFifoLatency;

                    // do windowing
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        fftWorksp[k] = { inFifo[k] * window[k], 0.0F };

                    // ***************** ANALYSIS *******************
                    // do transform
                    fft<-1, fftFrameSize>(fftWorksp);

                    // this is the analysis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const Complex<float>& current = fftWorksp[k];

                        // compute magnitude and phase
                        const float magn = 2.0F * current.magnitude();
                        const float signx = (current.imag > 0.0F) ? 1.0F : -1.0F;
                        const float phase = (current.imag == 0.0F) ? 0.0F :
                            (current.real == 0.0F) ? signx * pi / 2.0F :
                            std::atan2(current.imag, current.real);

                        // compute phase difference
                        float tmp = phase - lastPhase[k];
                        lastPhase[k] = phase;

                        // subtract expected phase difference
                        tmp -= static_cast<float>(k) * expected;

                        // map delta phase into +/- Pi interval
                        int32_t qpd = static_cast<int32_t>(tmp / pi);
                        if (qpd >= 0) qpd += qpd & 1;
                        else qpd -= qpd & 1;
                        tmp -= pi * static_cast<float>(qpd);

                        // get deviation from bin frequency from the +/- Pi interval
                        tmp = oversamp * tmp / (2.0F * pi);

                        // compute the k-th partials' true frequency
                        tmp = static_cast<float>(k) * freqPerBin + tmp * freqPerBin;

                        // store magnitude and true frequency in analysis arrays
                        anaMagn[k] = magn;
                        anaFreq[k] = tmp;
                    }

                    // ***************** PROCESSING *******************
                    // this does the actual pitch shifting
                    std::fill(std::begin(synMagn), std::begin(synMagn) + fftFrameSize, 0.0F);
                    std::fill(std::begin(synFreq), std::begin(synFreq) + fftFrameSize, 0.0F);
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const uint32_t index = static_cast<uint32_t>(k * pitchShift);
                        if (index > fftFrameSizeHalf) break;
                        synMagn[index] += anaMagn[k];
                        synFreq[index] = anaFreq[k] * pitchShift;
                    }

                    // ***************** SYNTHESIS *******************
                    // this is the synthesis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        // get magnitude and true frequency from synthesis arrays
                        const float magn = synMagn[k];
                        float tmp = synFreq[k];

                        // subtract bin mid frequency
                        tmp -= static_cast<float>(k) * freqPerBin;

                        // get bin deviation from freq deviation
                        tmp /= freqPerBin;

                        // take oversampling factor into account
                        tmp = 2.0F * pi * tmp / oversamp;

                        // add the overlap phase advance back in
                        tmp += static_cast<float>(k) * expected;

                        // accumulate delta phase to get bin phase
                        sumPhase[k] += tmp;
                        const float phase = sumPhase[k];

                        // get real and imag part and re-interleave
                        fftWorksp[k] = { magn * std::cos(phase), magn * std::sin(phase) };
                    }

                    // zero negative frequencies
                    for (uint32_t k = fftFrameSize + 1; k < fftFrameSize; ++k)
                        fftWorksp[k] = {0.0F, 0.0F};

                    // do inverse transform
                    fft<1, fftFrameSize>(fftWorksp);

                    // do windowing and add to output accumulator
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        outputAccum[k] += 2.0F * window[k] * fftWorksp[k].real / (fftFrameSizeHalf * oversamp);

                    uint32_t k;
                    for (k = 0 ; k < stepSize; ++k)
                        outFifo[k] = outputAccum[k];
                    // shift accumulator
                    uint32_t j;
                    for (j = 0; k < fftFrameSize; ++k, ++j)
                        outputAccum[j] = outputAccum[k];
                    for (; j < fftFrameSize; ++j)
                        outputAccum[j] = 0.0;

                    // move input FIFO
                    for (k = 0; k < inFifoLatency; ++k)
                        inFifo[k] = inFifo[k + stepSize];
                }
            }
        }

    private:
        float window[fftFrameSize]; // the windowing function
        float inFifo[fftFrameSize]{0.0F};
        float outFifo[fftFrameSize]{0.0F};
        Complex<float> fftWorksp[fftFrameSize]{{0.0F, 0.0F}};
        float lastPhase[fftFrameSize / 2 + 1]{0.0F};
        float sumPhase[fftFrameSize / 2 + 1]{0.0F};
        float outputAccum[2 * fftFrameSize]{0.0F};
        float anaFreq[fftFrameSize]{0.0F};
        float anaMagn[fftFrameSize]{0.0F};
        float synFreq[fftFrameSize]{0.0F};
        float synMagn[fftFrameSize]{0.0F};
        uint32_t rover = 0;
    };
}

#endif
<commit_msg>Make the frame and step sizes constexpr<commit_after>/****************************************************************************
*
* NAME: smbPitchShift.cpp
* VERSION: 1.2
* HOME URL: http://blogs.zynaptiq.com/bernsee
* KNOWN BUGS: none
*
* SYNOPSIS: Routine for doing pitch shifting while maintaining
* duration using the Short Time Fourier Transform.
*
* DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
* (one octave down) and 2. (one octave up). A value of exactly 1 does not change
* the pitch. numSampsToProcess tells the routine how many samples in indata[0...
* numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
* numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
* data in-place). fftFrameSize defines the FFT frame size used for the
* processing. Typical values are 1024, 2048 and 4096. It MUST be a power of 2.
* oversamp is the STFT oversampling factor which also determines the overlap
* between adjacent STFT frames. It should at least be 4 for moderate scaling
* ratios. A value of 32 is recommended for best quality. sampleRate takes the
* sample rate for the signal in unit Hz, ie. 44100 for 44.1 kHz audio. The data
* passed to the routine in indata[] should be in the range [-1.0, 1.0), which is
* also the output range for the data, make sure you scale the data accordingly
* (for 16bit signed integers you would have to divide (and multiply) by 32768).
*
* COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
*
* 						The Wide Open License (WOL)
*
* Permission to use, copy, modify, distribute and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice and this license appear in all source copies.
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*
*****************************************************************************/

#ifndef SMBPITCHSHIFT_HPP
#define SMBPITCHSHIFT_HPP

#include <algorithm>
#include <cmath>
#include <cstdint>

namespace smb
{
    namespace
    {
        constexpr float pi = 3.14159265358979323846F;

        // Use own implementation because std::complex has a poor performance
        template <class T>
        struct Complex final
        {
            constexpr Complex<T> operator+(const Complex& other) const noexcept
            {
                return Complex{real + other.real, imag + other.imag};
            }

            constexpr Complex<T>& operator+=(const Complex& other)
            {
                real += other.real;
                imag += other.imag;
                return *this;
            }

            constexpr Complex<T> operator-(const Complex& other) const noexcept
            {
                return Complex{real - other.real, imag - other.imag};
            }

            constexpr Complex<T> operator-() const noexcept
            {
                return Complex{-real, -imag};
            }

            constexpr Complex<T>& operator-=(const Complex& other) noexcept
            {
                real -= other.real;
                imag -= other.imag;
                return *this;
            }

            constexpr Complex<T> operator*(const Complex& other) const noexcept
            {
                return Complex{real * other.real - imag * other.imag, real * other.imag + imag * other.real};
            }

            constexpr Complex<T>& operator*=(const Complex& other) noexcept
            {
                float tempReal = real;
                real = tempReal * other.real - imag * other.imag;
                imag = tempReal * other.imag + imag * other.real;
                return *this;
            }

            inline T magnitude() const noexcept
            {
                return sqrt(real * real + imag * imag);
            }

            T real;
            T imag;
        };

        template <int32_t sign, uint32_t fftFrameSize>
        void fft(Complex<float>* fftBuffer) noexcept
        {
            // Bit-reversal permutation applied to a sequence of fftFrameSize items
            for (uint32_t i = 1; i < fftFrameSize - 1; ++i)
            {
                uint32_t j = 0;

                for (uint32_t bitm = 1; bitm < fftFrameSize; bitm <<= 1)
                {
                    if (i & bitm) ++j;
                    j <<= 1;
                }
                j >>= 1;

                if (i < j)
                    std::swap(fftBuffer[i], fftBuffer[j]);
            }

            // Iterative form of Danielson-Lanczos lemma
            uint32_t step = 2;
            for (uint32_t i = 1; i < fftFrameSize; i <<= 1, step <<= 1)
            {
                const uint32_t step2 = step >> 1;
                const float arg = pi / step2;

                const Complex<float> w{std::cos(arg), std::sin(arg) * sign};
                Complex<float> u{1.0F, 0.0F};
                for (uint32_t j = 0; j < step2; ++j)
                {
                    for (uint32_t k = j; k < fftFrameSize; k += step)
                    {
                        const Complex<float> temp = fftBuffer[k + step2] * u;
                        fftBuffer[k + step2] = fftBuffer[k] - temp;
                        fftBuffer[k] += temp;
                    }

                    u *= w;
                }
            }
        }
    }

    template <uint32_t fftFrameSize, uint32_t oversamp>
    class PitchShift final
    {
    public:
        PitchShift()
        {
            // Hann window
            for (uint32_t k = 0; k < fftFrameSize; ++k)
                window[k] = 0.5F * (1.0F + std::cos(2.0F * pi * static_cast<float>(k) / static_cast<float>(fftFrameSize)));
        }

        /*
            Routine process(). See top of file for explanation
            Purpose: doing pitch shifting while maintaining duration using the Short
            Time Fourier Transform.
            Author: (c)1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
        */
        void process(const float pitchShift, const uint32_t numSampsToProcess,
                     const uint32_t sampleRate, const float* indata, float* outdata) noexcept
        {
            // set up some handy variables
            constexpr uint32_t fftFrameSizeHalf = fftFrameSize / 2;
            constexpr uint32_t stepSize = fftFrameSize / oversamp;
            constexpr uint32_t inFifoLatency = fftFrameSize - stepSize;
            const float freqPerBin = static_cast<float>(sampleRate) / static_cast<float>(fftFrameSize);
            const float expected = 2.0F * pi * static_cast<float>(stepSize) / static_cast<float>(fftFrameSize);
            if (rover == 0) rover = inFifoLatency;

            // main processing loop
            for (uint32_t i = 0; i < numSampsToProcess; ++i)
            {
                // As long as we have not yet collected enough data just read in
                inFifo[rover] = indata[i];
                outdata[i] = outFifo[rover - inFifoLatency];
                ++rover;

                // now we have enough data for processing
                if (rover >= fftFrameSize)
                {
                    rover = inFifoLatency;

                    // do windowing
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        fftWorksp[k] = { inFifo[k] * window[k], 0.0F };

                    // ***************** ANALYSIS *******************
                    // do transform
                    fft<-1, fftFrameSize>(fftWorksp);

                    // this is the analysis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const Complex<float>& current = fftWorksp[k];

                        // compute magnitude and phase
                        const float magn = 2.0F * current.magnitude();
                        const float signx = (current.imag > 0.0F) ? 1.0F : -1.0F;
                        const float phase = (current.imag == 0.0F) ? 0.0F :
                            (current.real == 0.0F) ? signx * pi / 2.0F :
                            std::atan2(current.imag, current.real);

                        // compute phase difference
                        float tmp = phase - lastPhase[k];
                        lastPhase[k] = phase;

                        // subtract expected phase difference
                        tmp -= static_cast<float>(k) * expected;

                        // map delta phase into +/- Pi interval
                        int32_t qpd = static_cast<int32_t>(tmp / pi);
                        if (qpd >= 0) qpd += qpd & 1;
                        else qpd -= qpd & 1;
                        tmp -= pi * static_cast<float>(qpd);

                        // get deviation from bin frequency from the +/- Pi interval
                        tmp = oversamp * tmp / (2.0F * pi);

                        // compute the k-th partials' true frequency
                        tmp = static_cast<float>(k) * freqPerBin + tmp * freqPerBin;

                        // store magnitude and true frequency in analysis arrays
                        anaMagn[k] = magn;
                        anaFreq[k] = tmp;
                    }

                    // ***************** PROCESSING *******************
                    // this does the actual pitch shifting
                    std::fill(std::begin(synMagn), std::begin(synMagn) + fftFrameSize, 0.0F);
                    std::fill(std::begin(synFreq), std::begin(synFreq) + fftFrameSize, 0.0F);
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        const uint32_t index = static_cast<uint32_t>(k * pitchShift);
                        if (index > fftFrameSizeHalf) break;
                        synMagn[index] += anaMagn[k];
                        synFreq[index] = anaFreq[k] * pitchShift;
                    }

                    // ***************** SYNTHESIS *******************
                    // this is the synthesis step
                    for (uint32_t k = 0; k < fftFrameSizeHalf + 1; ++k)
                    {
                        // get magnitude and true frequency from synthesis arrays
                        const float magn = synMagn[k];
                        float tmp = synFreq[k];

                        // subtract bin mid frequency
                        tmp -= static_cast<float>(k) * freqPerBin;

                        // get bin deviation from freq deviation
                        tmp /= freqPerBin;

                        // take oversampling factor into account
                        tmp = 2.0F * pi * tmp / oversamp;

                        // add the overlap phase advance back in
                        tmp += static_cast<float>(k) * expected;

                        // accumulate delta phase to get bin phase
                        sumPhase[k] += tmp;
                        const float phase = sumPhase[k];

                        // get real and imag part and re-interleave
                        fftWorksp[k] = { magn * std::cos(phase), magn * std::sin(phase) };
                    }

                    // zero negative frequencies
                    for (uint32_t k = fftFrameSize + 1; k < fftFrameSize; ++k)
                        fftWorksp[k] = {0.0F, 0.0F};

                    // do inverse transform
                    fft<1, fftFrameSize>(fftWorksp);

                    // do windowing and add to output accumulator
                    for (uint32_t k = 0; k < fftFrameSize; ++k)
                        outputAccum[k] += 2.0F * window[k] * fftWorksp[k].real / (fftFrameSizeHalf * oversamp);

                    uint32_t k;
                    for (k = 0 ; k < stepSize; ++k)
                        outFifo[k] = outputAccum[k];
                    // shift accumulator
                    uint32_t j;
                    for (j = 0; k < fftFrameSize; ++k, ++j)
                        outputAccum[j] = outputAccum[k];
                    for (; j < fftFrameSize; ++j)
                        outputAccum[j] = 0.0;

                    // move input FIFO
                    for (k = 0; k < inFifoLatency; ++k)
                        inFifo[k] = inFifo[k + stepSize];
                }
            }
        }

    private:
        float window[fftFrameSize]; // the windowing function
        float inFifo[fftFrameSize]{0.0F};
        float outFifo[fftFrameSize]{0.0F};
        Complex<float> fftWorksp[fftFrameSize]{{0.0F, 0.0F}};
        float lastPhase[fftFrameSize / 2 + 1]{0.0F};
        float sumPhase[fftFrameSize / 2 + 1]{0.0F};
        float outputAccum[2 * fftFrameSize]{0.0F};
        float anaFreq[fftFrameSize]{0.0F};
        float anaMagn[fftFrameSize]{0.0F};
        float synFreq[fftFrameSize]{0.0F};
        float synMagn[fftFrameSize]{0.0F};
        uint32_t rover = 0;
    };
}

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: cacheitem.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2004-01-28 15:07:38 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __FILTER_CONFIG_CACHEITEM_HXX_
#define __FILTER_CONFIG_CACHEITEM_HXX_

//_______________________________________________
// includes

#include <hash_map>
#include <deque>

#ifndef _COM_SUN_STAR_UNO_ANY_H_
#include <com/sun/star/uno/Any.h>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_H_
#include <com/sun/star/uno/Sequence.h>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifndef _COM_SUN_STAR_BEANS_NAMEDVALUE_HPP_
#include <com/sun/star/beans/NamedValue.hpp>
#endif

#ifndef _COMPHELPER_SEQUENCEASVECTOR_HXX_
#include <comphelper/sequenceasvector.hxx>
#endif

#ifndef _COMPHELPER_SEQUENCEASHASHMAP_HXX_
#include <comphelper/sequenceashashmap.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

//_______________________________________________
// namespace

namespace filter{
    namespace config{

namespace css = ::com::sun::star;

//_______________________________________________
// definitions

/** @short  Must be used as first derived base class
            to get a full initialized mutex member,
            which can be used during the ctor runs too!
 */
struct BaseLock
{
    public:

        // must be mutable to be useable in const environments too!
        mutable ::osl::Mutex m_aLock;
};

typedef ::comphelper::SequenceAsVector< ::rtl::OUString > OUStringList;

//_______________________________________________

/** @short  represent an item of a FilterCache
            instance.

    @descr  This class is not threadsafe tp perform
            operations, which use many instances of
            this class! Synchronizations must be done outside.
 */
class CacheItem : public ::comphelper::SequenceAsHashMap
{
    //-------------------------------------------
    public:

        //---------------------------------------
        /** @short  creates an empty item.
          */
        CacheItem();

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

        /** @short  update only properties, which are given by the
                    specified rItem.

            @descr  Update means: - add new properties
                                  - change existing values

            @param  rUpdateItem
                    another cache item, which contains some special
                    properties, which should by used for updating
                    this one.
         */
        void update(const CacheItem& rUpdateItem);

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

        /** @short  check, if the given properties exists
                    at this item.

            @descr  All properties are compared in its minimum.
                    E.g: string lists => only the requested items
                    are checked. Additional existing items are ignored.

            @param  lProps
                    contains all properties, which must exist at this item.

            @return TRUE if all given properties exists
                    at this item; FALSE otherwhise.
         */
        sal_Bool haveProps(const CacheItem& lProps) const;

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

        /** @short  check, if the given properties dont exists
                    at this item.

            @descr  All properties are compared in its minimum.
                    E.g: string lists => only the requested items
                    are checked. Additional existing items are ignored.

            @param  lProps
                    contains all properties, which should not exists at this item.

            @return FALSE if at least on property exists at this item(!);
                    TRUE otherwhise.
         */
        sal_Bool dontHaveProps(const CacheItem& lProps) const;

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

        /** @short  check, if the given properties dont exists
                    at this item.

            @descr  All properties are compared in its minimum.
                    E.g: string lists => only the specified items
                    are checked. Additional existing items are ignored.

            @param  lProps
                    contains all properties, which should be checked.

            @return TRUE if all given properties dont exists
                    at this item; FALSE otherwhise.
         */
        sal_Bool excludeProps(const CacheItem& lProps) const;

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

        /** @short  because we know two UIName properties
                    (a list with all locales and the value
                    for the current locale only), we must be shure
                    that the correspond together.

            @param  sActLocale
                    must specify the current office locale.
                    Its needed to adress the UIName property inside
                    the list of possible ones.
         */
        void validateUINames(const ::rtl::OUString& sActLocale);

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

        /** @short  convert this structure to a seq< PropertyValue >
                    and ignore all empty properties!

            @descr  Normaly the converter routines of the base class
                    SequenceAsHashMap do this job already.
                    But it doesnt provide a "pack" mechanism to
                    ignore properties with empty (means "void") values.

            @return css::uno::Sequence< css::beans::PropertyValue >
                    as a list of all properties of this cacheitem,
                    where empty properties was removed.
         */
        css::uno::Sequence< css::beans::PropertyValue > getAsPackedPropertyValueList();
};

//_______________________________________________

/** @short  represent an item list of a FilterCache
            instance.
 */
typedef ::std::hash_map< ::rtl::OUString                    ,
                         CacheItem                          ,
                         ::rtl::OUStringHash                ,
                         ::std::equal_to< ::rtl::OUString > > CacheItemList;

//_______________________________________________

/** @short  supports registration of multiple key to
            another string information.

    @descr  E.g. a list of internal type names can be registered
            to an extension. Organization as an hash makes it
            faster then searching inside vectors.

            On the other side e.g. URLPattern cant be realy adressed
            by a hash value ... because the use wildcards. But
            there we need key-value pairs too, which cant be provided
            by a pur vector!
 */
typedef ::std::hash_map< ::rtl::OUString                    ,
                         OUStringList                       ,
                         ::rtl::OUStringHash                ,
                         ::std::equal_to< ::rtl::OUString > > CacheItemRegistration;

//_______________________________________________

/** @short  is used to collect all matching types of an URL
            during type detection.

    @descr  Every type in this list is combined with an information,
            which property matched to the given URL. The user of this
            structure can decide then, if a deep detection should be
            supressed e.g. if an URLPattern was used.

            Structure info: NamedValue.Name  = <internal type name>
                            NamedValue.Value = [boolean]bMatchByURLPattern
 */
typedef ::std::vector< css::beans::NamedValue > FlatDetection;

    } // namespace config
} // namespace filter

#endif // __FILTER_CONFIG_CACHEITEM_HXX_
<commit_msg>INTEGRATION: CWS imprec01 (1.2.178); FILE MERGED 2005/01/05 12:38:19 as 1.2.178.1: #i39653# make it possible to insert preferred types on the front of flat detection list<commit_after>/*************************************************************************
 *
 *  $RCSfile: cacheitem.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-02-02 13:46:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __FILTER_CONFIG_CACHEITEM_HXX_
#define __FILTER_CONFIG_CACHEITEM_HXX_

//_______________________________________________
// includes

#include <hash_map>
#include <deque>
#include <list>

#ifndef _COM_SUN_STAR_UNO_ANY_H_
#include <com/sun/star/uno/Any.h>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_H_
#include <com/sun/star/uno/Sequence.h>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifndef _COM_SUN_STAR_BEANS_NAMEDVALUE_HPP_
#include <com/sun/star/beans/NamedValue.hpp>
#endif

#ifndef _COMPHELPER_SEQUENCEASVECTOR_HXX_
#include <comphelper/sequenceasvector.hxx>
#endif

#ifndef _COMPHELPER_SEQUENCEASHASHMAP_HXX_
#include <comphelper/sequenceashashmap.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

//_______________________________________________
// namespace

namespace filter{
    namespace config{

namespace css = ::com::sun::star;

//_______________________________________________
// definitions

/** @short  Must be used as first derived base class
            to get a full initialized mutex member,
            which can be used during the ctor runs too!
 */
struct BaseLock
{
    public:

        // must be mutable to be useable in const environments too!
        mutable ::osl::Mutex m_aLock;
};

typedef ::comphelper::SequenceAsVector< ::rtl::OUString > OUStringList;

//_______________________________________________

/** @short  represent an item of a FilterCache
            instance.

    @descr  This class is not threadsafe tp perform
            operations, which use many instances of
            this class! Synchronizations must be done outside.
 */
class CacheItem : public ::comphelper::SequenceAsHashMap
{
    //-------------------------------------------
    public:

        //---------------------------------------
        /** @short  creates an empty item.
          */
        CacheItem();

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

        /** @short  update only properties, which are given by the
                    specified rItem.

            @descr  Update means: - add new properties
                                  - change existing values

            @param  rUpdateItem
                    another cache item, which contains some special
                    properties, which should by used for updating
                    this one.
         */
        void update(const CacheItem& rUpdateItem);

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

        /** @short  check, if the given properties exists
                    at this item.

            @descr  All properties are compared in its minimum.
                    E.g: string lists => only the requested items
                    are checked. Additional existing items are ignored.

            @param  lProps
                    contains all properties, which must exist at this item.

            @return TRUE if all given properties exists
                    at this item; FALSE otherwhise.
         */
        sal_Bool haveProps(const CacheItem& lProps) const;

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

        /** @short  check, if the given properties dont exists
                    at this item.

            @descr  All properties are compared in its minimum.
                    E.g: string lists => only the requested items
                    are checked. Additional existing items are ignored.

            @param  lProps
                    contains all properties, which should not exists at this item.

            @return FALSE if at least on property exists at this item(!);
                    TRUE otherwhise.
         */
        sal_Bool dontHaveProps(const CacheItem& lProps) const;

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

        /** @short  check, if the given properties dont exists
                    at this item.

            @descr  All properties are compared in its minimum.
                    E.g: string lists => only the specified items
                    are checked. Additional existing items are ignored.

            @param  lProps
                    contains all properties, which should be checked.

            @return TRUE if all given properties dont exists
                    at this item; FALSE otherwhise.
         */
        sal_Bool excludeProps(const CacheItem& lProps) const;

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

        /** @short  because we know two UIName properties
                    (a list with all locales and the value
                    for the current locale only), we must be shure
                    that the correspond together.

            @param  sActLocale
                    must specify the current office locale.
                    Its needed to adress the UIName property inside
                    the list of possible ones.
         */
        void validateUINames(const ::rtl::OUString& sActLocale);

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

        /** @short  convert this structure to a seq< PropertyValue >
                    and ignore all empty properties!

            @descr  Normaly the converter routines of the base class
                    SequenceAsHashMap do this job already.
                    But it doesnt provide a "pack" mechanism to
                    ignore properties with empty (means "void") values.

            @return css::uno::Sequence< css::beans::PropertyValue >
                    as a list of all properties of this cacheitem,
                    where empty properties was removed.
         */
        css::uno::Sequence< css::beans::PropertyValue > getAsPackedPropertyValueList();
};

//_______________________________________________

/** @short  represent an item list of a FilterCache
            instance.
 */
typedef ::std::hash_map< ::rtl::OUString                    ,
                         CacheItem                          ,
                         ::rtl::OUStringHash                ,
                         ::std::equal_to< ::rtl::OUString > > CacheItemList;

//_______________________________________________

/** @short  supports registration of multiple key to
            another string information.

    @descr  E.g. a list of internal type names can be registered
            to an extension. Organization as an hash makes it
            faster then searching inside vectors.

            On the other side e.g. URLPattern cant be realy adressed
            by a hash value ... because the use wildcards. But
            there we need key-value pairs too, which cant be provided
            by a pur vector!
 */
typedef ::std::hash_map< ::rtl::OUString                    ,
                         OUStringList                       ,
                         ::rtl::OUStringHash                ,
                         ::std::equal_to< ::rtl::OUString > > CacheItemRegistration;

//_______________________________________________

/** @short  is used to collect all matching types of an URL
            during type detection.

    @descr  Every type in this list is combined with an information,
            which property matched to the given URL. The user of this
            structure can decide then, if a deep detection should be
            supressed e.g. if an URLPattern was used.

            Structure info: NamedValue.Name  = <internal type name>
                            NamedValue.Value = [boolean]bMatchByURLPattern
 */
typedef ::std::list< css::beans::NamedValue > FlatDetection;

    } // namespace config
} // namespace filter

#endif // __FILTER_CONFIG_CACHEITEM_HXX_
<|endoftext|>


<commit_before>#define COUNTERHELPER_CALLBACKMODE
#include "CounterHelper.h"
#undef COUNTERHELPER_CALLBACKMODE

#include <ROOT/RDataFrame.hxx>
#include <ROOT/RTrivialDS.hxx>
#include <TROOT.h> // ROOT::EnableImplicitMT
#include <TFile.h>
#include <TSystem.h>
#include <TTree.h>

#include <gtest/gtest.h>

#include <algorithm> // std::min
#include <thread> // std::hardware_concurrency

// fixture for all tests in this file
struct RDFDataBlockCallback : ::testing::TestWithParam<bool> {
   unsigned int NSLOTS;
   unsigned int NENTRIES = std::max(10u, std::thread::hardware_concurrency() * 2);

   RDFDataBlockCallback() : NSLOTS(GetParam() ? std::min(4u, std::thread::hardware_concurrency()) : 1u)
   {
      if (GetParam())
         ROOT::EnableImplicitMT();
   }

   ~RDFDataBlockCallback()
   {
      if (GetParam())
         ROOT::DisableImplicitMT();
   }
};

// A RAII object that ensures existence of nFiles root files named prefix0.root, prefix1.root, ...
// Each file contains a TTree called "t" with one `int` branch called "x" with sequentially increasing values (0,1,2...)
struct InputFilesRAII {
   unsigned int fNFiles = 0;
   std::string fPrefix;

   InputFilesRAII(unsigned int nFiles, std::string prefix) : fNFiles(nFiles), fPrefix(std::move(prefix))
   {
      for (auto i = 0u; i < fNFiles; ++i) {
         TFile f((fPrefix + std::to_string(i) + ".root").c_str(), "recreate");
         TTree t("t", "t");
         t.Branch("x", &i);
         t.Fill();
         t.Write();
      }
   }

   ~InputFilesRAII()
   {
      for (auto i = 0u; i < fNFiles; ++i)
         gSystem->Unlink((fPrefix + std::to_string(i) + ".root").c_str());
   }
};

TEST_P(RDFDataBlockCallback, EmptySource) {
   ROOT::RDataFrame df(NENTRIES);
   auto result = df.Book<>(CounterHelper(), {});
   // RDF with empty sources tries to produce 2 tasks per slot when MT is enabled
   const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots() * 2u) : 1u;
   EXPECT_EQ(*result, expected);
}

TEST_P(RDFDataBlockCallback, DataSource) {
   auto df = ROOT::RDF::MakeTrivialDataFrame(NENTRIES);
   auto result = df.Book<>(CounterHelper(), {});
   // RTrivialDS tries to produce NSLOTS tasks
   const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots()) : 1u;
   EXPECT_EQ(*result, expected);
}

TEST_P(RDFDataBlockCallback, TTree) {
   const std::string prefix = "rdfdatablockcallback_ttree";
   InputFilesRAII file(1u, prefix);
   ROOT::RDataFrame df("t", prefix + "*");
   auto result = df.Book<>(CounterHelper(), {});
   EXPECT_EQ(*result, 1u);
}

TEST_P(RDFDataBlockCallback, TChain) {
   const std::string prefix = "rdfdatablockcallback_tchain";
   InputFilesRAII file(5u, prefix);
   ROOT::RDataFrame df("t", prefix + "*");
   auto result = df.Book<>(CounterHelper(), {});
   EXPECT_EQ(*result, 5u);
}

// instantiate single-thread tests
INSTANTIATE_TEST_SUITE_P(Seq, RDFDataBlockCallback, ::testing::Values(false));

#ifdef R__USE_IMT
   // instantiate multi-thread tests
   INSTANTIATE_TEST_SUITE_P(MT, RDFDataBlockCallback, ::testing::Values(true));
#endif
<commit_msg>[DF] Add test for data-block IDs<commit_after>#define COUNTERHELPER_CALLBACKMODE
#include "CounterHelper.h"
#undef COUNTERHELPER_CALLBACKMODE

#include <ROOT/RDataFrame.hxx>
#include <ROOT/RTrivialDS.hxx>
#include <TROOT.h> // ROOT::EnableImplicitMT
#include <TFile.h>
#include <TSystem.h>
#include <TTree.h>

#include <gtest/gtest.h>

#include <algorithm> // std::min
#include <memory>
#include <mutex>
#include <thread> // std::hardware_concurrency

// fixture for all tests in this file
struct RDFDataBlockCallback : ::testing::TestWithParam<bool> {
   unsigned int NSLOTS;
   unsigned int NENTRIES = std::max(10u, std::thread::hardware_concurrency() * 2);

   RDFDataBlockCallback() : NSLOTS(GetParam() ? std::min(4u, std::thread::hardware_concurrency()) : 1u)
   {
      if (GetParam())
         ROOT::EnableImplicitMT();
   }

   ~RDFDataBlockCallback()
   {
      if (GetParam())
         ROOT::DisableImplicitMT();
   }
};

// A RAII object that ensures existence of nFiles root files named prefix0.root, prefix1.root, ...
// Each file contains a TTree called "t" with one `int` branch called "x" with sequentially increasing values (0,1,2...)
struct InputFilesRAII {
   unsigned int fNFiles = 0;
   std::string fPrefix;

   InputFilesRAII(unsigned int nFiles, std::string prefix) : fNFiles(nFiles), fPrefix(std::move(prefix))
   {
      for (auto i = 0u; i < fNFiles; ++i) {
         TFile f((fPrefix + std::to_string(i) + ".root").c_str(), "recreate");
         TTree t("t", "t");
         t.Branch("x", &i);
         t.Fill();
         t.Write();
      }
   }

   ~InputFilesRAII()
   {
      for (auto i = 0u; i < fNFiles; ++i)
         gSystem->Unlink((fPrefix + std::to_string(i) + ".root").c_str());
   }
};

TEST_P(RDFDataBlockCallback, EmptySource) {
   ROOT::RDataFrame df(NENTRIES);
   auto result = df.Book<>(CounterHelper(), {});
   // RDF with empty sources tries to produce 2 tasks per slot when MT is enabled
   const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots() * 2u) : 1u;
   EXPECT_EQ(*result, expected);
}

TEST_P(RDFDataBlockCallback, DataSource) {
   auto df = ROOT::RDF::MakeTrivialDataFrame(NENTRIES);
   auto result = df.Book<>(CounterHelper(), {});
   // RTrivialDS tries to produce NSLOTS tasks
   const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots()) : 1u;
   EXPECT_EQ(*result, expected);
}

TEST_P(RDFDataBlockCallback, TTree) {
   const std::string prefix = "rdfdatablockcallback_ttree";
   InputFilesRAII file(1u, prefix);
   ROOT::RDataFrame df("t", prefix + "*");
   auto result = df.Book<>(CounterHelper(), {});
   EXPECT_EQ(*result, 1u);
}

TEST_P(RDFDataBlockCallback, TChain) {
   const std::string prefix = "rdfdatablockcallback_tchain";
   InputFilesRAII file(5u, prefix);
   ROOT::RDataFrame df("t", prefix + "*");
   auto result = df.Book<>(CounterHelper(), {});
   EXPECT_EQ(*result, 5u);
}

class DataBlockHelper : public ROOT::Detail::RDF::RActionImpl<DataBlockHelper> {
   std::shared_ptr<std::vector<ROOT::RDF::RDataBlockID>> fDataBlocks;
   std::unique_ptr<std::mutex> fMutex;
public:
   DataBlockHelper()
      : fDataBlocks(std::make_shared<std::vector<ROOT::RDF::RDataBlockID>>()), fMutex(std::make_unique<std::mutex>())
   {
   }
   DataBlockHelper(DataBlockHelper &&) = default;
   DataBlockHelper(const DataBlockHelper &) = delete;

   using Result_t = std::vector<ROOT::RDF::RDataBlockID>;
   auto GetResultPtr() const { return fDataBlocks; }
   void Initialize() {}
   void InitTask(TTreeReader *, unsigned int) {}
   void Exec(unsigned int) {}
   ROOT::RDF::DataBlockCallback_t GetDataBlockCallback() final
   {
      return [this](unsigned int, const ROOT::RDF::RDataBlockID &db) mutable {
         std::lock_guard<std::mutex> lg(*fMutex);
         fDataBlocks->emplace_back(db);
      };
   }
   void Finalize() {}

   std::string GetActionName() { return "DataBlockHelper"; }
};

TEST_P(RDFDataBlockCallback, EmptySourceDataBlockNames) {
   ROOT::RDataFrame df(NENTRIES);
   auto result = df.Book<>(DataBlockHelper(), {});
   if (ROOT::IsImplicitMTEnabled()) {
      // RDF with empty sources tries to produce 2 tasks per slot when MT is enabled
      const auto expectedSize = std::min(NENTRIES, df.GetNSlots() * 2u);
      ASSERT_EQ(result->size(), expectedSize);
      for (auto &id : *result) {
         // check that all entries start with the expected string
         EXPECT_TRUE(id.AsString().rfind("Empty source, range: {", 0) == 0);
      }
   } else {
      const std::string expectedStr = "Empty source, range: {0, " + std::to_string(NENTRIES) + "}";
      EXPECT_EQ(result->at(0).AsString(), expectedStr);
   }
}

TEST_P(RDFDataBlockCallback, TTreeDataBlockNames) {
   const std::string prefix = "rdfdatablockcallback_ttreedbnames";
   InputFilesRAII file(1u, prefix);
   ROOT::RDataFrame df("t", prefix + "*");
   auto result = df.Book<>(DataBlockHelper(), {});
   ASSERT_EQ(result->size(), 1u);
   EXPECT_TRUE(result->at(0).Contains(prefix));
   EXPECT_TRUE(result->at(0).AsString().rfind("/t") == result->at(0).AsString().size() - 2);
}

TEST_P(RDFDataBlockCallback, TChainDataBlockNames) {
   const std::string prefix = "rdfdatablockcallback_tchain";
   InputFilesRAII file(5u, prefix);
   ROOT::RDataFrame df("t", prefix + "*");
   auto result = df.Book<>(DataBlockHelper(), {});
   ASSERT_EQ(result->size(), 5u);
   std::vector<char> fileNumbers(5);
   for (auto i = 0u; i < 5u; ++i) {
      EXPECT_TRUE(result->at(i).Contains(prefix));
      const auto &id = result->at(i).AsString();
      EXPECT_TRUE(id.rfind("/t") == id.size() - 2);
      fileNumbers[i] = id[id.size() - 8];
   }

   std::sort(fileNumbers.begin(), fileNumbers.end());
   for (int i = 0; i < 5; ++i)
      // '0' == 48, '1' == 49, etc.
      EXPECT_EQ(fileNumbers[i], i + 48);
}

/* TODO: data-block IDs for RDataSources are not supported yet
TEST_P(RDFDataBlockCallback, DataSource) {
   auto df = ROOT::RDF::MakeTrivialDataFrame(NENTRIES);
   auto result = df.Book<>(CounterHelper(), {});
   // RTrivialDS tries to produce NSLOTS tasks
   const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots()) : 1u;
   EXPECT_EQ(*result, expected);
}
*/

// instantiate single-thread tests
INSTANTIATE_TEST_SUITE_P(Seq, RDFDataBlockCallback, ::testing::Values(false));

#ifdef R__USE_IMT
   // instantiate multi-thread tests
   INSTANTIATE_TEST_SUITE_P(MT, RDFDataBlockCallback, ::testing::Values(true));
#endif
<|endoftext|>


<commit_before>/**************************************************************************
 * newbucket.hxx -- new bucket routines for better world modeling
 *
 * Written by Curtis L. Olson, started February 1999.
 *
 * Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *
 * $Id$
 **************************************************************************/

/** \file newbucket.hxx
 * A class and associated utiltity functions to manage world scenery tiling.
 */

#ifndef _NEWBUCKET_HXX
#define _NEWBUCKET_HXX

#include <simgear/compiler.h>
#include <simgear/constants.h>

#ifdef SG_HAVE_STD_INCLUDES
#  include <cmath>
#  include <cstdio> // sprintf()
#else
#  include <math.h>
#  include <stdio.h> // sprintf()
#endif

#include STL_IOSTREAM

// I don't understand ... <math.h> or <cmath> should be included
// already depending on how you defined SG_HAVE_STD_INCLUDES, but I
// can go ahead and add this -- CLO
#ifdef __MWERKS__
SG_USING_STD(sprintf);
SG_USING_STD(fabs);
#endif

#include STL_STRING

SG_USING_STD(string);
SG_USING_STD(ostream);

/**
 * standard size of a bucket in degrees (1/8 of a degree)
 */
#define SG_BUCKET_SPAN      0.125

/**
 * half of a standard SG_BUCKET_SPAN
 */
#define SG_HALF_BUCKET_SPAN ( 0.5 * SG_BUCKET_SPAN )

// return the horizontal tile span factor based on latitude
static double sg_bucket_span( double l ) {
    if ( l >= 89.0 ) {
	return 360.0;
    } else if ( l >= 88.0 ) {
	return 8.0;
    } else if ( l >= 86.0 ) {
	return 4.0;
    } else if ( l >= 83.0 ) {
	return 2.0;
    } else if ( l >= 76.0 ) {
	return 1.0;
    } else if ( l >= 62.0 ) {
	return 0.5;
    } else if ( l >= 22.0 ) {
	return 0.25;
    } else if ( l >= -22.0 ) {
	return 0.125;
    } else if ( l >= -62.0 ) {
	return 0.25;
    } else if ( l >= -76.0 ) {
	return 0.5;
    } else if ( l >= -83.0 ) {
	return 1.0;
    } else if ( l >= -86.0 ) {
	return 2.0;
    } else if ( l >= -88.0 ) {
	return 4.0;
    } else if ( l >= -89.0 ) {
	return 8.0;
    } else {
	return 360.0;
    }
}

/**
 * A class to manage world scenery tiling.
 * This class encapsulates the world tiling scheme.  It provides ways
 * to calculate a unique tile index from a lat/lon, and it can provide
 * information such as the dimensions of a given tile.
 */

class SGBucket {

private:
    double cx, cy;  // centerpoint (lon, lat) in degrees of bucket
    int lon;        // longitude index (-180 to 179)
    int lat;        // latitude index (-90 to 89)
    int x;          // x subdivision (0 to 7)
    int y;          // y subdivision (0 to 7)

public:

    /**
     * Default constructor.
     */
    SGBucket();

    /**
     * Construct a bucket given a specific location.
     * @param dlon longitude specified in degrees
     * @param dlat latitude specified in degrees
     */
    SGBucket(const double dlon, const double dlat);

    /** Construct a bucket.
     *  @param is_good if false, create an invalid bucket.  This is
     *  useful * if you are comparing cur_bucket to last_bucket and
     *  you want to * make sure last_bucket starts out as something
     *  impossible.
     */
    SGBucket(const bool is_good);

    /** Construct a bucket given a unique bucket index number.
     * @param bindex unique bucket index
     */
    SGBucket(const long int bindex);

    /**
     * Default destructor.
     */
    ~SGBucket();

    /**
     * Reset a bucket to represent a new lat and lon
     * @param dlon longitude specified in degrees
     * @param dlat latitude specified in degrees
     */
    void set_bucket( double dlon, double dlat );

    /**
     * Reset a bucket to represent a new lat and lon
     * @param lonlat an array of double[2] holding lon and lat
     * (specified) in degrees
     */
    void set_bucket( double *lonlat );

    /**
     * Create an impossible bucket.
     * This is useful if you are comparing cur_bucket to last_bucket
     * and you want to make sure last_bucket starts out as something
     * impossible.
     */
    inline void make_bad() {
	set_bucket(0.0, 0.0);
	lon = -1000;
    }

    /**
     * Generate the unique scenery tile index for this bucket
     *
     * The index is constructed as follows:
     *
     * 9 bits - to represent 360 degrees of longitude (-180 to 179)
     * 8 bits - to represent 180 degrees of latitude (-90 to 89)
     *
     * Each 1 degree by 1 degree tile is further broken down into an 8x8
     * grid.  So we also need:
     *
     * 3 bits - to represent x (0 to 7)
     * 3 bits - to represent y (0 to 7)
     * @return tile index
     */
    inline long int gen_index() const {
	return ((lon + 180) << 14) + ((lat + 90) << 6) + (y << 3) + x;
    }

    /**
     * Generate the unique scenery tile index for this bucket in ascii
     * string form.
     * @return tile index in string form
     */
    inline string gen_index_str() const {
	char tmp[20];
	sprintf(tmp, "%ld",
                (((long)lon + 180) << 14) + ((lat + 90) << 6) + (y << 3) + x);
	return (string)tmp;
    }

    /**
     * Build the base path name for this bucket.
     * @return base path in string form
     */
    string gen_base_path() const;

    /**
     * @return the center lon of a tile.
     */
    inline double get_center_lon() const {
	double span = sg_bucket_span( lat + y / 8.0 + SG_HALF_BUCKET_SPAN );

	if ( span >= 1.0 ) {
	    return lon + span / 2.0;
	} else {
	    return lon + x * span + span / 2.0;
	}
    }

    /**
     * @return the center lat of a tile.
     */
    inline double get_center_lat() const {
	return lat + y / 8.0 + SG_HALF_BUCKET_SPAN;
    }

    /**
     * @return the width of the tile in degrees.
     */
    double get_width() const;

    /**
     * @return the height of the tile in degrees.
     */
    double get_height() const;

    /**
     * @return the width of the tile in meters.
     */
    double get_width_m() const;

    /**
     * @return the height of the tile in meters.
     */
    double get_height_m() const;

    // Informational methods.

    /**
     * @return the lon of the lower left corner of this tile.
     */
    inline int get_lon() const { return lon; }

    /**
     * @return the lat of the lower left corner of this tile.
     */
    inline int get_lat() const { return lat; }

    /**
     * @return the x coord within the 1x1 degree chunk this tile.
     */
    inline int get_x() const { return x; }

    /**
     * @return the y coord within the 1x1 degree chunk this tile.
     */
    inline int get_y() const { return y; }

    // friends

    friend ostream& operator<< ( ostream&, const SGBucket& );
    friend bool operator== ( const SGBucket&, const SGBucket& );
};

/**
 * \relates SGBucket
 * Return the bucket which is offset from the specified dlon, dlat by
 * the specified tile units in the X & Y direction.
 * @param dlon starting lon in degrees
 * @param dlat starting lat in degrees
 * @param x number of bucket units to offset in x (lon) direction
 * @param y number of bucket units to offset in y (lat) direction
 * @return offset bucket
 */
SGBucket sgBucketOffset( double dlon, double dlat, int x, int y );

/**
 * \relates SGBucket
 * Calculate the offset between two buckets (in quantity of buckets).
 * @param b1 bucket 1
 * @param b2 bucket 2
 * @param dx offset distance (lon) in tile units
 * @param dy offset distance (lat) in tile units
 */
void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy );

/**
 * Write the bucket lon, lat, x, and y to the output stream.
 * @param out output stream
 * @param b bucket
 */
inline ostream&
operator<< ( ostream& out, const SGBucket& b )
{
    return out << b.lon << ":" << b.x << ", " << b.lat << ":" << b.y;
}

/**
 * Compare two bucket structures for equality.
 * @param b1 bucket 1
 * @param b2 bucket 2
 * @return comparison result
 */
inline bool
operator== ( const SGBucket& b1, const SGBucket& b2 )
{
    return ( b1.lon == b2.lon &&
	     b1.lat == b2.lat &&
	     b1.x == b2.x &&
	     b1.y == b2.y );
}

#endif // _NEWBUCKET_HXX

<commit_msg>David Luff:<commit_after>/**************************************************************************
 * newbucket.hxx -- new bucket routines for better world modeling
 *
 * Written by Curtis L. Olson, started February 1999.
 *
 * Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *
 * $Id$
 **************************************************************************/

/** \file newbucket.hxx
 * A class and associated utiltity functions to manage world scenery tiling.
 */

#ifndef _NEWBUCKET_HXX
#define _NEWBUCKET_HXX

#include <simgear/compiler.h>
#include <simgear/constants.h>

#ifdef SG_HAVE_STD_INCLUDES
#  include <cmath>
#  include <cstdio> // sprintf()
#else
#  include <math.h>
#  include <stdio.h> // sprintf()
#endif

#include STL_IOSTREAM

// I don't understand ... <math.h> or <cmath> should be included
// already depending on how you defined SG_HAVE_STD_INCLUDES, but I
// can go ahead and add this -- CLO
#ifdef __MWERKS__
SG_USING_STD(sprintf);
SG_USING_STD(fabs);
#endif

#include STL_STRING

SG_USING_STD(string);
SG_USING_STD(ostream);

/**
 * standard size of a bucket in degrees (1/8 of a degree)
 */
#define SG_BUCKET_SPAN      0.125

/**
 * half of a standard SG_BUCKET_SPAN
 */
#define SG_HALF_BUCKET_SPAN ( 0.5 * SG_BUCKET_SPAN )

// return the horizontal tile span factor based on latitude
static double sg_bucket_span( double l ) {
    if ( l >= 89.0 ) {
	return 360.0;
    } else if ( l >= 88.0 ) {
	return 8.0;
    } else if ( l >= 86.0 ) {
	return 4.0;
    } else if ( l >= 83.0 ) {
	return 2.0;
    } else if ( l >= 76.0 ) {
	return 1.0;
    } else if ( l >= 62.0 ) {
	return 0.5;
    } else if ( l >= 22.0 ) {
	return 0.25;
    } else if ( l >= -22.0 ) {
	return 0.125;
    } else if ( l >= -62.0 ) {
	return 0.25;
    } else if ( l >= -76.0 ) {
	return 0.5;
    } else if ( l >= -83.0 ) {
	return 1.0;
    } else if ( l >= -86.0 ) {
	return 2.0;
    } else if ( l >= -88.0 ) {
	return 4.0;
    } else if ( l >= -89.0 ) {
	return 8.0;
    } else {
	return 360.0;
    }
}

/**
 * A class to manage world scenery tiling.
 * This class encapsulates the world tiling scheme.  It provides ways
 * to calculate a unique tile index from a lat/lon, and it can provide
 * information such as the dimensions of a given tile.
 */

class SGBucket {

private:
    double cx, cy;  // centerpoint (lon, lat) in degrees of bucket
    int lon;        // longitude index (-180 to 179)
    int lat;        // latitude index (-90 to 89)
    int x;          // x subdivision (0 to 7)
    int y;          // y subdivision (0 to 7)

public:

    /**
     * Default constructor.
     */
    SGBucket();

    /**
     * Construct a bucket given a specific location.
     * @param dlon longitude specified in degrees
     * @param dlat latitude specified in degrees
     */
    SGBucket(const double dlon, const double dlat);

    /** Construct a bucket.
     *  @param is_good if false, create an invalid bucket.  This is
     *  useful * if you are comparing cur_bucket to last_bucket and
     *  you want to * make sure last_bucket starts out as something
     *  impossible.
     */
    SGBucket(const bool is_good);

    /** Construct a bucket given a unique bucket index number.
     * @param bindex unique bucket index
     */
    SGBucket(const long int bindex);

    /**
     * Default destructor.
     */
    ~SGBucket();

    /**
     * Reset a bucket to represent a new lat and lon
     * @param dlon longitude specified in degrees
     * @param dlat latitude specified in degrees
     */
    void set_bucket( double dlon, double dlat );

    /**
     * Reset a bucket to represent a new lat and lon
     * @param lonlat an array of double[2] holding lon and lat
     * (specified) in degrees
     */
    void set_bucket( double *lonlat );

    /**
     * Create an impossible bucket.
     * This is useful if you are comparing cur_bucket to last_bucket
     * and you want to make sure last_bucket starts out as something
     * impossible.
     */
    inline void make_bad() {
	set_bucket(0.0, 0.0);
	lon = -1000;
    }

    /**
     * Generate the unique scenery tile index for this bucket
     *
     * The index is constructed as follows:
     *
     * 9 bits - to represent 360 degrees of longitude (-180 to 179)
     * 8 bits - to represent 180 degrees of latitude (-90 to 89)
     *
     * Each 1 degree by 1 degree tile is further broken down into an 8x8
     * grid.  So we also need:
     *
     * 3 bits - to represent x (0 to 7)
     * 3 bits - to represent y (0 to 7)
     * @return tile index
     */
    inline long int gen_index() const {
	return ((lon + 180) << 14) + ((lat + 90) << 6) + (y << 3) + x;
    }

    /**
     * Generate the unique scenery tile index for this bucket in ascii
     * string form.
     * @return tile index in string form
     */
    inline string gen_index_str() const {
	char tmp[20];
	sprintf(tmp, "%ld",
                (((long)lon + 180) << 14) + ((lat + 90) << 6) + (y << 3) + x);
	return (string)tmp;
    }

    /**
     * Build the base path name for this bucket.
     * @return base path in string form
     */
    string gen_base_path() const;

    /**
     * @return the center lon of a tile.
     */
    inline double get_center_lon() const {
	double span = sg_bucket_span( lat + y / 8.0 + SG_HALF_BUCKET_SPAN );

	if ( span >= 1.0 ) {
	    return lon + span / 2.0;
	} else {
	    return lon + x * span + span / 2.0;
	}
    }

    /**
     * @return the center lat of a tile.
     */
    inline double get_center_lat() const {
	return lat + y / 8.0 + SG_HALF_BUCKET_SPAN;
    }

    /**
     * @return the width of the tile in degrees.
     */
    double get_width() const;

    /**
     * @return the height of the tile in degrees.
     */
    double get_height() const;

    /**
     * @return the width of the tile in meters.
     */
    double get_width_m() const;

    /**
     * @return the height of the tile in meters.
     */
    double get_height_m() const;

    // Informational methods.

    /**
     * @return the lon of the lower left corner of
     * the 1x1 chunk containing this tile.
     */
    inline int get_lon() const { return lon; }

    /**
     * @return the lat of the lower left corner of
     * the 1x1 chunk containing this tile.
     */
    inline int get_lat() const { return lat; }

    /**
     * @return the x coord within the 1x1 degree chunk this tile.
     */
    inline int get_x() const { return x; }

    /**
     * @return the y coord within the 1x1 degree chunk this tile.
     */
    inline int get_y() const { return y; }

    // friends

    friend ostream& operator<< ( ostream&, const SGBucket& );
    friend bool operator== ( const SGBucket&, const SGBucket& );
};

/**
 * \relates SGBucket
 * Return the bucket which is offset from the specified dlon, dlat by
 * the specified tile units in the X & Y direction.
 * @param dlon starting lon in degrees
 * @param dlat starting lat in degrees
 * @param x number of bucket units to offset in x (lon) direction
 * @param y number of bucket units to offset in y (lat) direction
 * @return offset bucket
 */
SGBucket sgBucketOffset( double dlon, double dlat, int x, int y );

/**
 * \relates SGBucket
 * Calculate the offset between two buckets (in quantity of buckets).
 * @param b1 bucket 1
 * @param b2 bucket 2
 * @param dx offset distance (lon) in tile units
 * @param dy offset distance (lat) in tile units
 */
void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy );

/**
 * Write the bucket lon, lat, x, and y to the output stream.
 * @param out output stream
 * @param b bucket
 */
inline ostream&
operator<< ( ostream& out, const SGBucket& b )
{
    return out << b.lon << ":" << b.x << ", " << b.lat << ":" << b.y;
}

/**
 * Compare two bucket structures for equality.
 * @param b1 bucket 1
 * @param b2 bucket 2
 * @return comparison result
 */
inline bool
operator== ( const SGBucket& b1, const SGBucket& b2 )
{
    return ( b1.lon == b2.lon &&
	     b1.lat == b2.lat &&
	     b1.x == b2.x &&
	     b1.y == b2.y );
}

#endif // _NEWBUCKET_HXX

<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// audioio-rtnull.cpp: Null audio object with realtime behaviour
// Copyright (C) 1999,2002 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#include <cmath>
#include <iostream>
#include <string>
#include <time.h>

#include <kvutils/dbc.h>
#include <kvutils/kvutils.h>

#include "audioio-device.h"
#include "audioio-rtnull.h"

#include "eca-error.h"
#include "eca-debug.h"

using std::cerr;
using std::endl;

/**
 * Definitions from glibc's sys/time.h
 */

#ifndef timerclear
#define	timerclear(tvp)		((tvp)->tv_sec = (tvp)->tv_usec = 0)
#endif

#ifndef timeradd
#define	timeradd(a, b, result)						      \
  do {									      \
    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;			      \
    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;			      \
    if ((result)->tv_usec >= 1000000)					      \
      {									      \
	++(result)->tv_sec;						      \
	(result)->tv_usec -= 1000000;					      \
      }									      \
  } while (0)
#endif

#ifndef timercmp
#define	timercmp(a, b, CMP) 						      \
  (((a)->tv_sec == (b)->tv_sec) ? 					      \
   ((a)->tv_usec CMP (b)->tv_usec) : 					      \
   ((a)->tv_sec CMP (b)->tv_sec))
#endif

#ifndef timersub
#define	timersub(a, b, result) \
do { \
	(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
	(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
	if ((result)->tv_usec < 0) { \
		--(result)->tv_sec; \
		(result)->tv_usec += 1000000; \
	} \
} while (0)
#endif

/**
 * Function definitions
 */

REALTIME_NULL::REALTIME_NULL(const std::string& name)
{
}

REALTIME_NULL::~REALTIME_NULL(void)
{
  if (is_open() == true && is_running()) stop();

  if (is_open() == true) {
    close();
  }
}

void REALTIME_NULL::open(void) throw (AUDIO_IO::SETUP_ERROR &)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) open");

  double t = static_cast<double>(buffersize()) / samples_per_second();

  buffer_length_rep.tv_sec = static_cast<time_t>(floor(t));
  buffer_length_rep.tv_usec = static_cast<long>((t - buffer_length_rep.tv_sec) * 1000000.0);

  total_buffers_rep = 2;
  if (max_buffers() == true) {
    total_buffers_rep = 3;
  }
  total_buffer_length_rep.tv_sec = total_buffers_rep * buffer_length_rep.tv_sec;
  total_buffer_length_rep.tv_usec = total_buffers_rep * buffer_length_rep.tv_usec;

  AUDIO_IO_DEVICE::open();
}

void REALTIME_NULL::close(void)
{
  AUDIO_IO_DEVICE::close();
}

void REALTIME_NULL::prepare(void)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) prepare");

  timerclear(&data_processed_rep);

  AUDIO_IO_DEVICE::prepare();
}

void REALTIME_NULL::start(void)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) start");

  gettimeofday(&start_time_rep, NULL);

  AUDIO_IO_DEVICE::start();
}

void REALTIME_NULL::stop(void)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) stop");

  AUDIO_IO_DEVICE::stop();
}

/**
 * Calculates 'time_since_start_rep'.
 */
void REALTIME_NULL::calculate_device_position(void)
{
  struct timeval now;
  gettimeofday(&now, NULL);

  timersub(&now, &start_time_rep, &time_since_start_rep);
}

/**
 * Calculates 'avail_data_rep'.
 */
void REALTIME_NULL::calculate_available_data(void)
{
  if (io_mode() == io_read) {
    /* capture: device is always ahead */
    timersub(&time_since_start_rep, &data_processed_rep, &avail_data_rep);
  }
  else {
    /* playback: device is always behind */
    struct timeval diff;
    timersub(&data_processed_rep, &time_since_start_rep, &diff);
    timersub(&total_buffer_length_rep, &diff, &avail_data_rep);
  }
  if (timercmp(&avail_data_rep, &total_buffer_length_rep, >)) {
    cerr << "(audioio-rtnull) xrun occured!" << endl;
  }
}

void REALTIME_NULL::block_until_data_available(void)
{
  calculate_device_position();
  calculate_available_data();

  while (timercmp(&avail_data_rep, &buffer_length_rep, <)) {
    struct timeval delay;
    struct timespec ndelay;

    timersub(&buffer_length_rep, &avail_data_rep, &delay);

    ndelay.tv_sec = delay.tv_sec;
    ndelay.tv_nsec = delay.tv_usec * 1000;
    // cerr << "(audioio-rtnull) sleeping for: " << ndelay.tv_sec << " sec, " << ndelay.tv_nsec << " nanoseconds.\n";
    nanosleep(&ndelay, NULL);

    calculate_device_position();
    calculate_available_data();
  }
}

long int REALTIME_NULL::read_samples(void* target_buffer,
				     long int samples)
{
  DBC_CHECK(is_running() == true);

  for(int n = 0; n < samples * frame_size(); n++) ((char*)target_buffer)[n] = 0;

  block_until_data_available();

  /* read one buffer of audio */
  timeradd(&data_processed_rep, &buffer_length_rep, &data_processed_rep);

  return(buffersize());
}

void REALTIME_NULL::write_samples(void* target_buffer,
				  long int samples)
{
  if (is_running() != true) {
    /* prefill phase */

    /* write one buffer of audio */
    timeradd(&data_processed_rep, &buffer_length_rep, &data_processed_rep);
  }
  else {
    /* block until write space available */
    block_until_data_available();

    /* write one buffer of audio */
    timeradd(&data_processed_rep, &buffer_length_rep, &data_processed_rep);
  }
}

long int REALTIME_NULL::prefill_space(void) const
{
  if (io_mode() != io_read) return(total_buffers_rep * buffersize());
}

long int REALTIME_NULL::delay(void) const
{
  long int delay = 0;

  if (is_running() == true) {
    calculate_available_data();

    double time = avail_data_rep.tv_sec * 1000000.0 + avail_data_rep.tv_usec;
    delay = static_cast<SAMPLE_SPECS::sample_pos_t>
      (time * samples_per_second() / 1000000.0);
  }

  DBC_CHECK(delay >= 0);
  return(delay);
}
<commit_msg>Minor fixes; added missing const.<commit_after>// ------------------------------------------------------------------------
// audioio-rtnull.cpp: Null audio object with realtime behaviour
// Copyright (C) 1999,2002 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#include <cmath>
#include <iostream>
#include <string>
#include <time.h>

#include <kvutils/dbc.h>
#include <kvutils/kvutils.h>

#include "audioio-device.h"
#include "audioio-rtnull.h"

#include "eca-error.h"
#include "eca-debug.h"

using std::cerr;
using std::endl;

/**
 * Definitions from glibc's sys/time.h
 */

#ifndef timerclear
#define	timerclear(tvp)		((tvp)->tv_sec = (tvp)->tv_usec = 0)
#endif

#ifndef timeradd
#define	timeradd(a, b, result)						      \
  do {									      \
    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;			      \
    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;			      \
    if ((result)->tv_usec >= 1000000)					      \
      {									      \
	++(result)->tv_sec;						      \
	(result)->tv_usec -= 1000000;					      \
      }									      \
  } while (0)
#endif

#ifndef timercmp
#define	timercmp(a, b, CMP) 						      \
  (((a)->tv_sec == (b)->tv_sec) ? 					      \
   ((a)->tv_usec CMP (b)->tv_usec) : 					      \
   ((a)->tv_sec CMP (b)->tv_sec))
#endif

#ifndef timersub
#define	timersub(a, b, result) \
do { \
	(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
	(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
	if ((result)->tv_usec < 0) { \
		--(result)->tv_sec; \
		(result)->tv_usec += 1000000; \
	} \
} while (0)
#endif

/**
 * Function definitions
 */

REALTIME_NULL::REALTIME_NULL(const std::string& name)
{
}

REALTIME_NULL::~REALTIME_NULL(void)
{
  if (is_open() == true && is_running()) stop();

  if (is_open() == true) {
    close();
  }
}

void REALTIME_NULL::open(void) throw (AUDIO_IO::SETUP_ERROR &)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) open");

  double t = static_cast<double>(buffersize()) / samples_per_second();

  buffer_length_rep.tv_sec = static_cast<time_t>(floor(t));
  buffer_length_rep.tv_usec = static_cast<long>((t - buffer_length_rep.tv_sec) * 1000000.0);

  total_buffers_rep = 2;
  if (max_buffers() == true) {
    total_buffers_rep = 3;
  }
  total_buffer_length_rep.tv_sec = total_buffers_rep * buffer_length_rep.tv_sec;
  total_buffer_length_rep.tv_usec = total_buffers_rep * buffer_length_rep.tv_usec;

  AUDIO_IO_DEVICE::open();
}

void REALTIME_NULL::close(void)
{
  AUDIO_IO_DEVICE::close();
}

void REALTIME_NULL::prepare(void)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) prepare");

  timerclear(&data_processed_rep);

  AUDIO_IO_DEVICE::prepare();
}

void REALTIME_NULL::start(void)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) start");

  gettimeofday(&start_time_rep, NULL);

  AUDIO_IO_DEVICE::start();
}

void REALTIME_NULL::stop(void)
{
  ecadebug->msg(ECA_DEBUG::user_objects, "(audioio-rtnull) stop");

  AUDIO_IO_DEVICE::stop();
}

/**
 * Calculates 'time_since_start_rep'.
 */
void REALTIME_NULL::calculate_device_position(void)
{
  struct timeval now;
  gettimeofday(&now, NULL);

  timersub(&now, &start_time_rep, &time_since_start_rep);
}

/**
 * Calculates 'avail_data_rep'.
 */
void REALTIME_NULL::calculate_available_data(void) const
{
  if (io_mode() == io_read) {
    /* capture: device is always ahead */
    timersub(&time_since_start_rep, &data_processed_rep, &avail_data_rep);
  }
  else {
    /* playback: device is always behind */
    struct timeval diff;
    timersub(&data_processed_rep, &time_since_start_rep, &diff);
    timersub(&total_buffer_length_rep, &diff, &avail_data_rep);
  }
  if (timercmp(&avail_data_rep, &total_buffer_length_rep, >)) {
    cerr << "(audioio-rtnull) xrun occured!" << endl;
  }
}

void REALTIME_NULL::block_until_data_available(void)
{
  calculate_device_position();
  calculate_available_data();

  while (timercmp(&avail_data_rep, &buffer_length_rep, <)) {
    struct timeval delay;
    struct timespec ndelay;

    timersub(&buffer_length_rep, &avail_data_rep, &delay);

    ndelay.tv_sec = delay.tv_sec;
    ndelay.tv_nsec = delay.tv_usec * 1000;
    // cerr << "(audioio-rtnull) sleeping for: " << ndelay.tv_sec << " sec, " << ndelay.tv_nsec << " nanoseconds.\n";
    nanosleep(&ndelay, NULL);

    calculate_device_position();
    calculate_available_data();
  }
}

long int REALTIME_NULL::read_samples(void* target_buffer,
				     long int samples)
{
  DBC_CHECK(is_running() == true);

  for(int n = 0; n < samples * frame_size(); n++) ((char*)target_buffer)[n] = 0;

  block_until_data_available();

  /* read one buffer of audio */
  timeradd(&data_processed_rep, &buffer_length_rep, &data_processed_rep);

  return(buffersize());
}

void REALTIME_NULL::write_samples(void* target_buffer,
				  long int samples)
{
  if (is_running() != true) {
    /* prefill phase */

    /* write one buffer of audio */
    timeradd(&data_processed_rep, &buffer_length_rep, &data_processed_rep);
  }
  else {
    /* block until write space available */
    block_until_data_available();

    /* write one buffer of audio */
    timeradd(&data_processed_rep, &buffer_length_rep, &data_processed_rep);
  }
}

long int REALTIME_NULL::prefill_space(void) const
{
  if (io_mode() != io_read) return(total_buffers_rep * buffersize());
}

long int REALTIME_NULL::delay(void) const
{
  long int delay = 0;

  if (is_running() == true) {
    calculate_available_data();

    double time = avail_data_rep.tv_sec * 1000000.0 + avail_data_rep.tv_usec;
    delay = static_cast<SAMPLE_SPECS::sample_pos_t>
      (time * samples_per_second() / 1000000.0);
  }

  DBC_CHECK(delay >= 0);
  return(delay);
}
<|endoftext|>


<commit_before>#include "AssimpObjectManager.hpp"
#include "AssimpLoader.h"
#include "EntityManager.hpp"

#include <OgreSceneManager.h>

#include "OgreObjectComponent.hpp"
#include "components/GraphicsComponent.hpp"

#include <filesystem>

static AssimpLoader g_assimp;

AssimpObjectManager::AssimpObjectManager(kengine::EntityManager & em, Ogre::SceneManager & sceneManager)
	: _em(em), _sceneManager(sceneManager)
{
}

void AssimpObjectManager::registerEntity(kengine::Entity & e) noexcept {
	if (!e.has<kengine::GraphicsComponent>())
		return;

	const auto & graphics = e.get<kengine::GraphicsComponent>();

	OgreObjectComponent comp;

	Ogre::String finalName = graphics.appearance.c_str();
	Ogre::String extension, path;
	Ogre::StringUtil::splitFullFilename(graphics.appearance.c_str(), finalName, extension, path);

	if (extension == "mesh")
		return;

	finalName = finalName + "_" + extension + ".mesh";
	const auto fullPath = path + finalName;

	auto & resourceGroupManager = Ogre::ResourceGroupManager::getSingleton();

	if (!std::filesystem::exists(fullPath.c_str())) {
		AssimpLoader::AssOptions options;
		options.source = graphics.appearance;
		if (!g_assimp.convert(options))
			return;
	}

	// Cleanup after AssimpLoader::convert
	resourceGroupManager.removeResourceLocation(path);
	resourceGroupManager.removeResourceLocation("./resources");

	if (!resourceGroupManager.resourceLocationExists(path)) {
		resourceGroupManager.addResourceLocation(path, "FileSystem");
		resourceGroupManager.initialiseAllResourceGroups();
	}

	comp.entity = _sceneManager.createEntity(finalName);
	comp.node = _sceneManager.getRootSceneNode()->createChildSceneNode();
	comp.node->attachObject(comp.entity);

	e += comp;
}<commit_msg>made AssimpObjectManager use separate resource groups<commit_after>#include "AssimpObjectManager.hpp"
#include "AssimpLoader.h"
#include "EntityManager.hpp"

#include <OgreSceneManager.h>

#include "OgreObjectComponent.hpp"
#include "components/GraphicsComponent.hpp"

#include <filesystem>

AssimpObjectManager::AssimpObjectManager(kengine::EntityManager & em, Ogre::SceneManager & sceneManager)
	: _em(em), _sceneManager(sceneManager)
{
}

void AssimpObjectManager::registerEntity(kengine::Entity & e) noexcept {
	if (!e.has<kengine::GraphicsComponent>())
		return;

	const auto & graphics = e.get<kengine::GraphicsComponent>();

	OgreObjectComponent comp;

	Ogre::String finalName = graphics.appearance.c_str();
	Ogre::String extension, path;
	Ogre::StringUtil::splitFullFilename(graphics.appearance.c_str(), finalName, extension, path);

	if (extension == "mesh")
		return;

	finalName = finalName + "_" + extension + ".mesh";
	const auto fullPath = path + finalName;

	auto & resourceGroupManager = Ogre::ResourceGroupManager::getSingleton();

	if (!std::filesystem::exists(fullPath.c_str())) {
		AssimpLoader::AssOptions options;
		options.source = graphics.appearance;

		AssimpLoader loader;
		if (!loader.convert(options))
			return;
		// Cleanup after AssimpLoader::convert
		resourceGroupManager.removeResourceLocation(path);
		resourceGroupManager.removeResourceLocation("./resources");
	}

	if (!resourceGroupManager.resourceLocationExists(path)) {
		resourceGroupManager.addResourceLocation(path, "FileSystem", path);
		resourceGroupManager.initialiseAllResourceGroups();
	}

	comp.entity = _sceneManager.createEntity(finalName);
	comp.node = _sceneManager.getRootSceneNode()->createChildSceneNode();
	comp.node->attachObject(comp.entity);

	e += comp;
}<|endoftext|>