<commit_before>// This class
#include <Internal/ParticleClasses/ParticleEmitter.hpp>
//#include <FluidManager.hpp> // Included for the sake of particle data. Kinda silly, really
#include <Internal/PhysicsModuleImplementation.hpp>

// 3rd parties

using namespace DirectX;
using namespace physx;
namespace DoremiEngine
{
    namespace Physics
    {
        ParticleEmitter::ParticleEmitter(ParticleEmitterData p_data, InternalPhysicsUtils& p_utils)
            : m_this(p_data), m_utils(p_utils), m_timeSinceLast(0)
        {
            m_nextIndex = 0;
            m_particleSystem = m_utils.m_physics->createParticleSystem(PARTICLE_MAX_COUNT);
            m_particleSystem->setMaxMotionDistance(PARTICLE_MAX_MOTION_DISTANCE);
            m_particleSystem->setParticleReadDataFlag(PxParticleReadDataFlag::eVELOCITY_BUFFER, true);
            m_utils.m_worldScene->addActor(*m_particleSystem);
            // Might be necessary to set flag to collide with dynamics
            // m_particleSystem->setParticleBaseFlag(PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS, true);
            m_particleSystem->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); // Should not be here
        }
        ParticleEmitter::~ParticleEmitter() {}

        void ParticleEmitter::SetPosition(XMFLOAT3 p_position) { m_this.m_position = p_position; }
        void ParticleEmitter::SetDirection(XMFLOAT4 p_direction) { m_this.m_direction = p_direction; }
        void ParticleEmitter::SetGravity(bool p_gravity) { m_particleSystem->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, p_gravity); }

        void ParticleEmitter::GetPositions(vector<XMFLOAT3>& o_positions)
        {
            // This is a bit harder than it really ought to be...
            PxParticleReadData* readData = m_particleSystem->lockParticleReadData();
            PxStrideIterator<const PxVec3> positions = readData->positionBuffer;
            PxStrideIterator<const PxVec3> velocities = readData->velocityBuffer;
            PxStrideIterator<const PxParticleFlags> flags = readData->flagsBuffer;
            vector<XMFLOAT3> velocitiesVector;

            vector<int> indicesOfParticlesToBeReleased;

            uint32_t numParticles = readData->validParticleRange;
            for(uint32_t i = 0; i < numParticles; i++)
            {
                // Check if particles are supposed to be removed
                XMFLOAT3 position = XMFLOAT3(positions[i].x, positions[i].y, positions[i].z);
                XMFLOAT3 velocity = XMFLOAT3(velocities[i].x, velocities[i].y, velocities[i].z);
                XMVECTOR velVec = XMLoadFloat3(&velocity);
                velVec = XMVector3Normalize(velVec);
                XMStoreFloat3(&velocity, velVec); // TODOJB Remove normalization once it's fixed in CastRay
                if(flags[i] & (PxParticleFlag::eCOLLISION_WITH_DRAIN)) // | PxParticleFlag::eVALID))
                {
                    /// Particle should be removed
                    // Add index to release list
                    indicesOfParticlesToBeReleased.push_back(i);
                    // Find out which actor it collided with using ray tracing (seriously. It was this easy...)
                    m_drainsHit.push_back(m_utils.m_rayCastManager->CastRay(position, velocity, 5)); // Zero might turn up buggy
                }
                else if(flags[i] & PxParticleFlag::eVALID)
                {
                    o_positions.push_back(position);
                }
            }
            readData->unlock();
            if(indicesOfParticlesToBeReleased.size() != 0)
            {
                PxStrideIterator<const PxU32> inicesPX(reinterpret_cast<PxU32*>(&indicesOfParticlesToBeReleased[0]));
                m_particleSystem->releaseParticles(indicesOfParticlesToBeReleased.size(), inicesPX);
            }
        }

        vector<int> ParticleEmitter::GetDrainsHit() { return m_drainsHit; }

        void ParticleEmitter::SetData(ParticleEmitterData p_data) { m_this = p_data; }

        void ParticleEmitter::UpdateParticleLifeTimeAndRemoveExpired(float p_dt)
        {
            // Get particle indexData
            PxParticleReadData* t_particleData = m_particleSystem->lockParticleReadData();
            PX_ASSERT(t_particleData);
            std::vector<PxU32> t_indicesToRemove;
            PxU32 newvalidRange = 0;
            // Kolla om vi har ngra particlar som r valid annars ondigt att ens brja uppdatera
            if (t_particleData->validParticleRange > 0)
            {
                for (PxU32 i = 0; i <= (t_particleData->validParticleRange - 1) >> 5; i++)
                {
                    for (PxU32 j = t_particleData->validParticleBitmap[i]; j; j &= j - 1)
                    {
                        // TODOXX super unsafe. I am not sure what i am doing here. I was following a tutorial and a function they used was missing. This seems to be what they did essentially but WARNING!!
                        unsigned long b;
                        _BitScanForward(&b, j);
                        PxU32 t_index = (i << 5 | b);
                        if (m_particlesLifeTime[t_index] = -p_dt < 0.0)
                        {
                            m_particlesLifeTime[t_index] = 0;
                            t_indicesToRemove.push_back(t_index);
                        }

                    }
                }
                t_particleData->unlock();
                PxStrideIterator<const PxU32> t_indexData(&t_indicesToRemove[0]);
                m_particleSystem->releaseParticles(static_cast<PxU32>(t_indicesToRemove.size()), t_indexData);
                // TODOLH om vi skaffar indexPool kr m_indexpool->freeIndices(indices.size(), indexData);
            }
            else
            {
                // Do nothing
            }
        }

        void ParticleEmitter::Update(float p_dt)
        {
            m_drainsHit.clear();
            if(m_this.m_active)
            {
                // Update time since last particle wave was spawned
                m_timeSinceLast += p_dt;
                if(m_timeSinceLast > m_this.m_emissionRate)
                {
                    m_timeSinceLast = 0;
                    vector<XMFLOAT3> velocities;
                    vector<XMFLOAT3> positions;
                    vector<int> indices;
                    /// Time for more particles!
                    /// These particles will be spawned in a sort of grid (atm)
                    for(int x = -m_this.m_density; x < m_this.m_density * 2 - 1; x++)
                    {
                        for(int y = -m_this.m_density; y < m_this.m_density * 2; y++)
                        {
                            // Calculate angles in local space
                            float xAngle = (x / m_this.m_density) * m_this.m_emissionAreaDimensions.x;
                            float yAngle = (y / m_this.m_density) * m_this.m_emissionAreaDimensions.y;
                            // Define standard target in local space
                            XMVECTOR particleVelocityVec = XMLoadFloat3(&XMFLOAT3(0, 0, 1));
                            XMMATRIX rotMatLocal = XMMatrixRotationRollPitchYaw(xAngle, yAngle, 0);
                            particleVelocityVec = XMVector3Transform(particleVelocityVec, rotMatLocal);
                            // Move velocity vector into world space
                            XMMATRIX rotMatWorld = XMMatrixRotationQuaternion(XMLoadFloat4(&m_this.m_direction));
                            particleVelocityVec = XMVector3Transform(particleVelocityVec, rotMatWorld);
                            // Multiply with pressure
                            particleVelocityVec *= m_this.m_launchPressure;
                            // Store in vector
                            XMFLOAT3 velocity;
                            XMStoreFloat3(&velocity, particleVelocityVec);
                            velocities.push_back(velocity);

                            // Add position (only emitts from the center of the emitter atm
                            float launchOffset = 0.1f;
                            XMVECTOR positionVec = XMLoadFloat3(&m_this.m_position);
                            positionVec += launchOffset * particleVelocityVec;
                            XMFLOAT3 position;
                            XMStoreFloat3(&position, positionVec);

                            positions.push_back(position);

                            // Add index (silly way just to make it work atm)
                            indices.push_back(m_nextIndex);
                            // Set the lifetime of this particle TODOLH maybe add support for particles without lifetime. Some kind of bool. Hopefully we dont have to do this. Seems hard at first glance
                            m_particlesLifeTime[m_nextIndex] = m_lifeTime;
                            m_nextIndex++;
                        }
                    }

                    if(positions.size() > 0 && !(m_nextIndex > PARTICLE_MAX_COUNT)) // no point doing things if there's no new particles
                    {
                        // Cast into PhysX datatypes
                        PxVec3* positionsPX = reinterpret_cast<PxVec3*>(&positions[0]);
                        PxVec3* velocitiesPX = reinterpret_cast<PxVec3*>(&velocities[0]);
                        PxU32* indicesPX = reinterpret_cast<PxU32*>(&indices[0]);

                        // Create the particles
                        PxParticleCreationData newParticlesData;
                        newParticlesData.numParticles = positions.size();
                        newParticlesData.positionBuffer = PxStrideIterator<const PxVec3>(positionsPX);
                        newParticlesData.velocityBuffer = PxStrideIterator<const PxVec3>(velocitiesPX);
                        newParticlesData.indexBuffer = PxStrideIterator<const PxU32>(indicesPX);
                        m_particleSystem->createParticles(newParticlesData);
                    }
                    else
                    {
                        // No new particles. Do nothing
                    }
                }
            }
        }
    }
}<commit_msg>Added support for Particle Lifetime<commit_after>// This class
#include <Internal/ParticleClasses/ParticleEmitter.hpp>
//#include <FluidManager.hpp> // Included for the sake of particle data. Kinda silly, really
#include <Internal/PhysicsModuleImplementation.hpp>

// 3rd parties

using namespace DirectX;
using namespace physx;
namespace DoremiEngine
{
    namespace Physics
    {
        ParticleEmitter::ParticleEmitter(ParticleEmitterData p_data, InternalPhysicsUtils& p_utils)
            : m_this(p_data), m_utils(p_utils), m_timeSinceLast(0)
        {
            m_nextIndex = 0;
            m_particleSystem = m_utils.m_physics->createParticleSystem(PARTICLE_MAX_COUNT);
            m_particleSystem->setMaxMotionDistance(PARTICLE_MAX_MOTION_DISTANCE);
            m_particleSystem->setParticleReadDataFlag(PxParticleReadDataFlag::eVELOCITY_BUFFER, true);
            m_utils.m_worldScene->addActor(*m_particleSystem);
            // Might be necessary to set flag to collide with dynamics
            // m_particleSystem->setParticleBaseFlag(PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS, true);
            m_particleSystem->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); // Should not be here
        }
        ParticleEmitter::~ParticleEmitter() {}

        void ParticleEmitter::SetPosition(XMFLOAT3 p_position) { m_this.m_position = p_position; }
        void ParticleEmitter::SetDirection(XMFLOAT4 p_direction) { m_this.m_direction = p_direction; }
        void ParticleEmitter::SetGravity(bool p_gravity) { m_particleSystem->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, p_gravity); }

        void ParticleEmitter::GetPositions(vector<XMFLOAT3>& o_positions)
        {
            // This is a bit harder than it really ought to be...
            PxParticleReadData* readData = m_particleSystem->lockParticleReadData();
            PxStrideIterator<const PxVec3> positions = readData->positionBuffer;
            PxStrideIterator<const PxVec3> velocities = readData->velocityBuffer;
            PxStrideIterator<const PxParticleFlags> flags = readData->flagsBuffer;
            vector<XMFLOAT3> velocitiesVector;

            vector<int> indicesOfParticlesToBeReleased;

            uint32_t numParticles = readData->validParticleRange;
            for(uint32_t i = 0; i < numParticles; i++)
            {
                // Check if particles are supposed to be removed
                XMFLOAT3 position = XMFLOAT3(positions[i].x, positions[i].y, positions[i].z);
                XMFLOAT3 velocity = XMFLOAT3(velocities[i].x, velocities[i].y, velocities[i].z);
                XMVECTOR velVec = XMLoadFloat3(&velocity);
                velVec = XMVector3Normalize(velVec);
                XMStoreFloat3(&velocity, velVec); // TODOJB Remove normalization once it's fixed in CastRay
                if(flags[i] & (PxParticleFlag::eCOLLISION_WITH_DRAIN)) // | PxParticleFlag::eVALID))
                {
                    /// Particle should be removed
                    // Add index to release list
                    indicesOfParticlesToBeReleased.push_back(i);
                    // Find out which actor it collided with using ray tracing (seriously. It was this easy...)
                    m_drainsHit.push_back(m_utils.m_rayCastManager->CastRay(position, velocity, 5)); // Zero might turn up buggy
                }
                else if(flags[i] & PxParticleFlag::eVALID)
                {
                    o_positions.push_back(position);
                }
            }
            readData->unlock();
            if(indicesOfParticlesToBeReleased.size() != 0)
            {
                PxStrideIterator<const PxU32> inicesPX(reinterpret_cast<PxU32*>(&indicesOfParticlesToBeReleased[0]));
                m_particleSystem->releaseParticles(indicesOfParticlesToBeReleased.size(), inicesPX);
            }
        }

        vector<int> ParticleEmitter::GetDrainsHit() { return m_drainsHit; }

        void ParticleEmitter::SetData(ParticleEmitterData p_data) { m_this = p_data; }

        void ParticleEmitter::UpdateParticleLifeTimeAndRemoveExpired(float p_dt)
        {
            std::vector<PxU32> t_indicesToRemove;
            // Get particle indexData
            PxParticleReadData* t_particleData = m_particleSystem->lockParticleReadData();
            PX_ASSERT(t_particleData);
            // Kolla om vi har ngra particlar som r valid annars ondigt att ens brja uppdatera
            if(t_particleData->validParticleRange > 0)
            {
                int length = t_particleData->validParticleRange;

                for(PxU32 i = 0; i <= (t_particleData->validParticleRange - 1) >> 5; i++)
                {

                    for(PxU32 j = t_particleData->validParticleBitmap[i]; j; j &= j - 1)
                    {
                        // TODOXX super unsafe. I am not sure what i am doing here. I was following a tutorial and a function they used was missing.
                        // This seems to be what they did essentially but WARNING!!
                        // Get index from physx. you have to use bitoperations from their bittable for indices. Its pretty complicated and Im not 100%
                        // sure this code is safe
                        unsigned long b;
                        _BitScanForward(&b, j);
                        PxU32 t_index = (i << 5 | (PxU32)b);
                        // Update particle lifetime
                        m_particlesLifeTime[t_index] -= p_dt;
                        // CHeck if particle is still alive
                        if((m_particlesLifeTime[t_index]) < 0.0)
                        {
                            m_particlesLifeTime[t_index] = 0;
                            t_indicesToRemove.push_back(t_index);
                        }
                    }
                }
            }
            else
            {
                // Do nothing
            }
            // Release the data we have been looking at
            t_particleData->unlock();
            // Needs to not crash
            if(t_indicesToRemove.size() > 0)
            {
                // Need Stride for releaseparticle.
                PxStrideIterator<const PxU32> t_indexData(&t_indicesToRemove[0]);
                // Now release the particles that we want to remove
                m_particleSystem->releaseParticles(static_cast<PxU32>(t_indicesToRemove.size()), t_indexData);
                // TODOLH om vi skaffar indexPool kr m_indexpool->freeIndices(indices.size(), indexData);
            }
        }

        void ParticleEmitter::Update(float p_dt)
        {
            m_drainsHit.clear();
            UpdateParticleLifeTimeAndRemoveExpired(p_dt);
            if(m_this.m_active)
            {
                // Update time since last particle wave was spawned
                m_timeSinceLast += p_dt;
                if(m_timeSinceLast > m_this.m_emissionRate)
                {
                    m_timeSinceLast = 0;
                    vector<XMFLOAT3> velocities;
                    vector<XMFLOAT3> positions;
                    vector<int> indices;
                    /// Time for more particles!
                    /// These particles will be spawned in a sort of grid (atm)
                    for(int x = -m_this.m_density; x < m_this.m_density * 2 - 1; x++)
                    {
                        for(int y = -m_this.m_density; y < m_this.m_density * 2; y++)
                        {
                            // Calculate angles in local space
                            float xAngle = (x / m_this.m_density) * m_this.m_emissionAreaDimensions.x;
                            float yAngle = (y / m_this.m_density) * m_this.m_emissionAreaDimensions.y;
                            // Define standard target in local space
                            XMVECTOR particleVelocityVec = XMLoadFloat3(&XMFLOAT3(0, 0, 1));
                            XMMATRIX rotMatLocal = XMMatrixRotationRollPitchYaw(xAngle, yAngle, 0);
                            particleVelocityVec = XMVector3Transform(particleVelocityVec, rotMatLocal);
                            // Move velocity vector into world space
                            XMMATRIX rotMatWorld = XMMatrixRotationQuaternion(XMLoadFloat4(&m_this.m_direction));
                            particleVelocityVec = XMVector3Transform(particleVelocityVec, rotMatWorld);
                            // Multiply with pressure
                            particleVelocityVec *= m_this.m_launchPressure;
                            // Store in vector
                            XMFLOAT3 velocity;
                            XMStoreFloat3(&velocity, particleVelocityVec);
                            velocities.push_back(velocity);

                            // Add position (only emitts from the center of the emitter atm
                            float launchOffset = 0.1f;
                            XMVECTOR positionVec = XMLoadFloat3(&m_this.m_position);
                            positionVec += launchOffset * particleVelocityVec;
                            XMFLOAT3 position;
                            XMStoreFloat3(&position, positionVec);

                            positions.push_back(position);

                            // Add index (silly way just to make it work atm)
                            indices.push_back(m_nextIndex);
                            // Set the lifetime of this particle TODOLH maybe add support for particles without lifetime. Some kind of bool. Hopefully we dont have to do this. Seems hard at first glance
                            m_particlesLifeTime[m_nextIndex] = m_lifeTime;
                            m_nextIndex++;
                        }
                    }

                    if(positions.size() > 0 && !(m_nextIndex > PARTICLE_MAX_COUNT)) // no point doing things if there's no new particles
                    {
                        // Cast into PhysX datatypes
                        PxVec3* positionsPX = reinterpret_cast<PxVec3*>(&positions[0]);
                        PxVec3* velocitiesPX = reinterpret_cast<PxVec3*>(&velocities[0]);
                        PxU32* indicesPX = reinterpret_cast<PxU32*>(&indices[0]);

                        // Create the particles
                        PxParticleCreationData newParticlesData;
                        newParticlesData.numParticles = positions.size();
                        newParticlesData.positionBuffer = PxStrideIterator<const PxVec3>(positionsPX);
                        newParticlesData.velocityBuffer = PxStrideIterator<const PxVec3>(velocitiesPX);
                        newParticlesData.indexBuffer = PxStrideIterator<const PxU32>(indicesPX);
                        m_particleSystem->createParticles(newParticlesData);
                    }
                    else
                    {
                        // No new particles. Do nothing
                    }
                }
            }
        }
    }
}<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "ofLog.h"

#include "MidiThread.h"

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

MidiThread::MidiThread(Poco::FastMutex &synthMutex, NSynth &synth)
	: ofThread(), synthMutex(synthMutex), synth(synth){
}

bool MidiThread::setup(const std::string &device, int channel){
	this->channel = channel;

	// The device setup is performed twice to ensure it works on device
	// startup.

	for(int i=0; i<2; ++i){
		if(i != 0){
			close(deviceFd);
		}

		deviceFd = open(device.c_str(), O_RDONLY | O_NOCTTY);
		if(deviceFd < 0){
			ofLog(OF_LOG_WARNING) << "Failed to open MIDI input " << device;
			return false;
		}

		// Configure the serial port at 38400 baud. Settings on the Raspberry Pi
		// should adapt this to the MIDI baud rate of 31250.
		struct termios tty;
		memset(&tty, 0, sizeof tty);
		if(tcgetattr(deviceFd, &tty) != 0){
			return false;
		}

		cfsetospeed(&tty, B38400);
		cfsetispeed(&tty, B38400);

		tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
		tty.c_iflag &= ~IGNBRK;
		tty.c_lflag = 0;
		tty.c_oflag = 0;
		tty.c_cc[VMIN]  = 1;
		tty.c_cc[VTIME] = 0;

		tty.c_iflag &= ~(IXON | IXOFF | IXANY);

		tty.c_cflag |= (CLOCAL | CREAD);
		tty.c_cflag &= ~(PARENB | PARODD);
		tty.c_cflag &= ~CSTOPB;
		tty.c_cflag &= ~CRTSCTS;

		if(tcsetattr(deviceFd, TCSANOW, &tty) != 0){
			return false;
		}
	}

	return true;
}

void MidiThread::threadedFunction(){
	auto read1 = [this]()->uint8_t{
		uint8_t result;
		while(read(deviceFd, &result, 1) != 1){
			if(!isThreadRunning()){
				return 0xff;
			}
		}
		return result;
	};

	uint8_t header = read1();
	while(isThreadRunning()){
		if((header & 0xf0) == 0x90){
			// Note on - this is a 3 byte message.
			uint8_t note = read1();
			if(!isThreadRunning()){
				break;
			}
			if(note & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			uint8_t velocity = read1();
			if(!isThreadRunning()){
				break;
			}
			if(velocity & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			if((header & 0x0f) == channel){
				synthMutex.lock();
				synth.on(note, static_cast<float>(velocity) / 127.0f);
				synthMutex.unlock();
			}

			// Start on the next message.
			header = read1();
		}else if((header & 0xf0) == 0x80){
			// Note off - this is a 3 byte message.
			uint8_t note = read1();
			if(!isThreadRunning()){
				break;
			}
			if(note & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			uint8_t velocity = read1();
			if(!isThreadRunning()){
				break;
			}
			if(velocity & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			if((header & 0x0f) == channel){
				synthMutex.lock();
				synth.off(note);
				synthMutex.unlock();
			}

			// Start on the next message.
			header = read1();
		}else{
			// Discard the header as it is not understood.
			header = read1();
		}
	}
}
<commit_msg>Fix #43 by filtering out system real-time messages<commit_after>/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "ofLog.h"

#include "MidiThread.h"

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

MidiThread::MidiThread(Poco::FastMutex &synthMutex, NSynth &synth)
	: ofThread(), synthMutex(synthMutex), synth(synth){
}

bool MidiThread::setup(const std::string &device, int channel){
	this->channel = channel;

	// The device setup is performed twice to ensure it works on device
	// startup.

	for(int i=0; i<2; ++i){
		if(i != 0){
			close(deviceFd);
		}

		deviceFd = open(device.c_str(), O_RDONLY | O_NOCTTY);
		if(deviceFd < 0){
			ofLog(OF_LOG_WARNING) << "Failed to open MIDI input " << device;
			return false;
		}

		// Configure the serial port at 38400 baud. Settings on the Raspberry Pi
		// should adapt this to the MIDI baud rate of 31250.
		struct termios tty;
		memset(&tty, 0, sizeof tty);
		if(tcgetattr(deviceFd, &tty) != 0){
			return false;
		}

		cfsetospeed(&tty, B38400);
		cfsetispeed(&tty, B38400);

		tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
		tty.c_iflag &= ~IGNBRK;
		tty.c_lflag = 0;
		tty.c_oflag = 0;
		tty.c_cc[VMIN]  = 1;
		tty.c_cc[VTIME] = 0;

		tty.c_iflag &= ~(IXON | IXOFF | IXANY);

		tty.c_cflag |= (CLOCAL | CREAD);
		tty.c_cflag &= ~(PARENB | PARODD);
		tty.c_cflag &= ~CSTOPB;
		tty.c_cflag &= ~CRTSCTS;

		if(tcsetattr(deviceFd, TCSANOW, &tty) != 0){
			return false;
		}
	}

	return true;
}

void MidiThread::threadedFunction(){
	auto read1 = [this]()->uint8_t{
		uint8_t result;
		while(true) {
            if(!isThreadRunning()){
				return 0xff;
            }

			int readCount = read(deviceFd, &result, 1);
            if (readCount != 1) {
                continue;
            }

			// ignore system real time bytes
            if (result == 0xFE || result == 0xFF || result == 0xF8 || result == 0xFA || result == 0xFB || result == 0xFC) {
                continue;
            }

			return result;
		}
	};

	uint8_t header = read1();
	while(isThreadRunning()){
		if((header & 0xf0) == 0x90){
			// Note on - this is a 3 byte message.
			uint8_t note = read1();
			if(!isThreadRunning()){
				break;
			}
			if(note & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			uint8_t velocity = read1();
			if(!isThreadRunning()){
				break;
			}
			if(velocity & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			if((header & 0x0f) == channel){
				synthMutex.lock();
				synth.on(note, static_cast<float>(velocity) / 127.0f);
				synthMutex.unlock();
			}

			// Start on the next message.
			header = read1();
		}else if((header & 0xf0) == 0x80){
			// Note off - this is a 3 byte message.
			uint8_t note = read1();
			if(!isThreadRunning()){
				break;
			}
			if(note & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			uint8_t velocity = read1();
			if(!isThreadRunning()){
				break;
			}
			if(velocity & 0x80){
				// The note is badly formed, discard the current header
				// and continue;
				header = note;
				break;
			}

			if((header & 0x0f) == channel){
				synthMutex.lock();
				synth.off(note);
				synthMutex.unlock();
			}

			// Start on the next message.
			header = read1();
		}else{
			// Discard the header as it is not understood.
			header = read1();
		}
	}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: QueryViewSwitch.hxx,v $
 * $Revision: 1.14 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef DBAUI_QUERYVIEWSWITCH_HXX
#define DBAUI_QUERYVIEWSWITCH_HXX

#ifndef DBAUI_QUERYVIEW_HXX
#include "queryview.hxx"
#endif

namespace dbaui
{
    class OQueryDesignView;
    class OQueryTextView;
    class OAddTableDlg;
    class OQueryContainerWindow;
    class OQueryViewSwitch
    {
        OQueryDesignView*   m_pDesignView;
        OQueryTextView*     m_pTextView;
        sal_Bool            m_bAddTableDialogWasVisible; // true if so
    public:
        OQueryViewSwitch(OQueryContainerWindow* pParent, OQueryController* _pController,const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& );
        virtual ~OQueryViewSwitch();

        virtual sal_Bool isCutAllowed();
        virtual sal_Bool isPasteAllowed();
        virtual sal_Bool isCopyAllowed();
        virtual void copy();
        virtual void cut();
        virtual void paste();
        // clears the whole query
        virtual void clear();
        // set the view readonly or not
        virtual void setReadOnly(sal_Bool _bReadOnly);
        // check if the statement is correct when not returning false
        virtual sal_Bool checkStatement();
        // set the statement for representation
        virtual void setStatement(const ::rtl::OUString& _rsStatement);
        // returns the current sql statement
        virtual ::rtl::OUString getStatement();
        /// late construction
        virtual void Construct();
        virtual void initialize();
        /** show the text or the design view
            @return
                <TRUE/> when all went right otherwise <FALSE/> which implies an aditional
                call of switchView from the controller to restore the old state
        */
        sal_Bool switchView();
        sal_Bool isSlotEnabled(sal_Int32 _nSlotId);
        void     setSlotEnabled(sal_Int32 _nSlotId,sal_Bool _bEnable);
        void     setNoneVisbleRow(sal_Int32 _nRows);
        // returs the add table dialog from the design view
        OAddTableDlg* getAddTableDialog();
        void SaveUIConfig();
        void reset();
        void GrabFocus();

        OQueryDesignView*       getDesignView() const { return m_pDesignView; }
        OQueryContainerWindow*  getContainer() const;

        void SetPosSizePixel( Point _rPt,Size _rSize);
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > getORB() const;
    protected:
        // return the Rectangle where I can paint myself
        virtual void resizeDocumentView(Rectangle& rRect);
    };
}
#endif // DBAUI_QUERYVIEWSWITCH_HXX

<commit_msg>INTEGRATION: CWS dba30d (1.14.30); FILE MERGED 2008/05/29 11:25:58 fs 1.14.30.1: during #i80943#: refactoring: IController now passed around as reference, not as pointer<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: QueryViewSwitch.hxx,v $
 * $Revision: 1.15 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef DBAUI_QUERYVIEWSWITCH_HXX
#define DBAUI_QUERYVIEWSWITCH_HXX

#ifndef DBAUI_QUERYVIEW_HXX
#include "queryview.hxx"
#endif

namespace dbaui
{
    class OQueryDesignView;
    class OQueryTextView;
    class OAddTableDlg;
    class OQueryContainerWindow;
    class OQueryViewSwitch
    {
        OQueryDesignView*   m_pDesignView;
        OQueryTextView*     m_pTextView;
        sal_Bool            m_bAddTableDialogWasVisible; // true if so
    public:
        OQueryViewSwitch(OQueryContainerWindow* pParent, OQueryController& _rController,const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& );
        virtual ~OQueryViewSwitch();

        virtual sal_Bool isCutAllowed();
        virtual sal_Bool isPasteAllowed();
        virtual sal_Bool isCopyAllowed();
        virtual void copy();
        virtual void cut();
        virtual void paste();
        // clears the whole query
        virtual void clear();
        // set the view readonly or not
        virtual void setReadOnly(sal_Bool _bReadOnly);
        // check if the statement is correct when not returning false
        virtual sal_Bool checkStatement();
        // set the statement for representation
        virtual void setStatement(const ::rtl::OUString& _rsStatement);
        // returns the current sql statement
        virtual ::rtl::OUString getStatement();
        /// late construction
        virtual void Construct();
        virtual void initialize();
        /** show the text or the design view
            @return
                <TRUE/> when all went right otherwise <FALSE/> which implies an aditional
                call of switchView from the controller to restore the old state
        */
        sal_Bool switchView();
        sal_Bool isSlotEnabled(sal_Int32 _nSlotId);
        void     setSlotEnabled(sal_Int32 _nSlotId,sal_Bool _bEnable);
        void     setNoneVisbleRow(sal_Int32 _nRows);
        // returs the add table dialog from the design view
        OAddTableDlg* getAddTableDialog();
        void SaveUIConfig();
        void reset();
        void GrabFocus();

        OQueryDesignView*       getDesignView() const { return m_pDesignView; }
        OQueryContainerWindow*  getContainer() const;

        void SetPosSizePixel( Point _rPt,Size _rSize);
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > getORB() const;
    protected:
        // return the Rectangle where I can paint myself
        virtual void resizeDocumentView(Rectangle& rRect);
    };
}
#endif // DBAUI_QUERYVIEWSWITCH_HXX

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: RelationControl.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: oj $ $Date: 2002-11-08 09:27:37 $
 *
 *  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 DBAUI_RELATIONCONTROL_HXX
#define DBAUI_RELATIONCONTROL_HXX

#ifndef _FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif
#ifndef _SV_LSTBOX_HXX //autogen
#include <vcl/lstbox.hxx>
#endif
#ifndef DBAUI_JOINTABLEVIEW_HXX
#include "JoinTableView.hxx"
#endif

namespace dbaui
{
    //========================================================================
    class OTableListBoxControl;
    class OTableConnectionData;
    class ORelationTableConnectionData;
    class IRelationControlInterface;
    class ORelationControl;

    class OTableListBoxControl  : public Window
    {
        FixedLine                               m_aFL_InvolvedTables;
        ListBox                                 m_lmbLeftTable,
                                                m_lmbRightTable;
        FixedLine                               m_aFL_InvolvedFields;

        ORelationControl*                       m_pRC_Tables;
        const OJoinTableView::OTableWindowMap*  m_pTableMap;
        IRelationControlInterface*              m_pParentDialog;
        String                                  m_strCurrentLeft;
        String                                  m_strCurrentRight;
    private:
        DECL_LINK( OnTableChanged, ListBox* );
    public:
        OTableListBoxControl(Window* _pParent,
                             const ResId& _rResId,
                             const OJoinTableView::OTableWindowMap* _pTableMap,
                             IRelationControlInterface* _pParentDialog);
        virtual ~OTableListBoxControl();

        /** fillListBoxes fills the list boxes with the table windows
        */
        void fillListBoxes();

        /** fillAndDisable fill the listboxes only with one entry and then disable them
            @param  _pConnectionData
                    contains the data which should be filled into the listboxes
        */
        void fillAndDisable(OTableConnectionData* _pConnectionData);

        /** NotifyCellChange notifies the browse control that the conenction data has changed
        */
        void NotifyCellChange();

        /** Init is a call through to the control inside this one
            @param  _pConnData
                    the connection data which is used to init the control
        */
        void Init(OTableConnectionData* _pConnData);
        void lateInit();

        BOOL SaveModified();

        String getSourceWinName()   const;
        String getDestWinName()     const;

        /** getContainer returns the container interface
            @return the interface of the container
        */
        IRelationControlInterface* getContainer() const { return m_pParentDialog; }
    };
}
#endif // DBAUI_RELATIONCONTROL_HXX
<commit_msg>INTEGRATION: CWS ooo19126 (1.3.472); FILE MERGED 2005/09/05 17:34:24 rt 1.3.472.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: RelationControl.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:32:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/
#ifndef DBAUI_RELATIONCONTROL_HXX
#define DBAUI_RELATIONCONTROL_HXX

#ifndef _FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif
#ifndef _SV_LSTBOX_HXX //autogen
#include <vcl/lstbox.hxx>
#endif
#ifndef DBAUI_JOINTABLEVIEW_HXX
#include "JoinTableView.hxx"
#endif

namespace dbaui
{
    //========================================================================
    class OTableListBoxControl;
    class OTableConnectionData;
    class ORelationTableConnectionData;
    class IRelationControlInterface;
    class ORelationControl;

    class OTableListBoxControl  : public Window
    {
        FixedLine                               m_aFL_InvolvedTables;
        ListBox                                 m_lmbLeftTable,
                                                m_lmbRightTable;
        FixedLine                               m_aFL_InvolvedFields;

        ORelationControl*                       m_pRC_Tables;
        const OJoinTableView::OTableWindowMap*  m_pTableMap;
        IRelationControlInterface*              m_pParentDialog;
        String                                  m_strCurrentLeft;
        String                                  m_strCurrentRight;
    private:
        DECL_LINK( OnTableChanged, ListBox* );
    public:
        OTableListBoxControl(Window* _pParent,
                             const ResId& _rResId,
                             const OJoinTableView::OTableWindowMap* _pTableMap,
                             IRelationControlInterface* _pParentDialog);
        virtual ~OTableListBoxControl();

        /** fillListBoxes fills the list boxes with the table windows
        */
        void fillListBoxes();

        /** fillAndDisable fill the listboxes only with one entry and then disable them
            @param  _pConnectionData
                    contains the data which should be filled into the listboxes
        */
        void fillAndDisable(OTableConnectionData* _pConnectionData);

        /** NotifyCellChange notifies the browse control that the conenction data has changed
        */
        void NotifyCellChange();

        /** Init is a call through to the control inside this one
            @param  _pConnData
                    the connection data which is used to init the control
        */
        void Init(OTableConnectionData* _pConnData);
        void lateInit();

        BOOL SaveModified();

        String getSourceWinName()   const;
        String getDestWinName()     const;

        /** getContainer returns the container interface
            @return the interface of the container
        */
        IRelationControlInterface* getContainer() const { return m_pParentDialog; }
    };
}
#endif // DBAUI_RELATIONCONTROL_HXX
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of duicompositor.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QtDebug>

#include <MSceneManager>
#include <MScene>

#include <QApplication>
#include <QDesktopWidget>
#include <QX11Info>
#include <QGLFormat>
#include <QGLWidget>

#include "mdecoratorwindow.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xmd.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>

#include <mabstractdecorator.h>

class MDecorator: public MAbstractDecorator
{
    Q_OBJECT
public:
    MDecorator(MDecoratorWindow *p)
        : MAbstractDecorator(p),
        decorwindow(p)
    {
    }

    ~MDecorator() {
    }

    virtual void manageEvent(Qt::HANDLE window)
    {
        XTextProperty p;
        QString title;

        if(XGetWMName(QX11Info::display(), window, &p)) {
            if (p.value) {
                title = (char*) p.value;
                XFree(p.value);
            }
        }
        decorwindow->setInputRegion();
        setAvailableGeometry(decorwindow->availableClientRect());
        decorwindow->setWindowTitle(title);
    }

protected:
    virtual void activateEvent() {
    }

    virtual void setAutoRotation(bool mode)
    {
        Q_UNUSED(mode)
        // we follow the orientation of the topmost app
    }

    virtual void setOnlyStatusbar(bool mode)
    {
        decorwindow->setOnlyStatusbar(mode);
        decorwindow->setInputRegion();
        setAvailableGeometry(decorwindow->availableClientRect());
    }

private:

    MDecoratorWindow *decorwindow;
};

#if 0
static QRect windowRectFromGraphicsItem(const QGraphicsView &view,
                                        const QGraphicsItem &item)
{
    return view.mapFromScene(
               item.mapToScene(
                   item.boundingRect()
               )
           ).boundingRect();
}
#endif

MDecoratorWindow::MDecoratorWindow(QWidget *parent)
    : MWindow(parent)
{
    onlyStatusbarAtom = XInternAtom(QX11Info::display(),
                                    "_MDECORATOR_ONLY_STATUSBAR", False);
    managedWindowAtom = XInternAtom(QX11Info::display(),
                                    "_MDECORATOR_MANAGED_WINDOW", False);

    homeButtonPanel = new MHomeButtonPanel();
    escapeButtonPanel = new MEscapeButtonPanel();
    navigationBar = new MNavigationBar();
    statusBar = new MStatusBar();

    connect(homeButtonPanel, SIGNAL(buttonClicked()), this,
            SIGNAL(homeClicked()));
    connect(escapeButtonPanel, SIGNAL(buttonClicked()), this,
            SIGNAL(escapeClicked()));

    sceneManager()->appearSceneWindowNow(statusBar);
    setOnlyStatusbar(false);

    d = new MDecorator(this);
    connect(this, SIGNAL(homeClicked()), d, SLOT(minimize()));
    connect(this, SIGNAL(escapeClicked()), d, SLOT(close()));
    connect(sceneManager(),
            SIGNAL(orientationChanged(M::Orientation)),
            this,
            SLOT(screenRotated(M::Orientation)));

    setFocusPolicy(Qt::NoFocus);
    setSceneSize();
    setMDecoratorWindowProperty();

    setInputRegion();
    setProperty("followsCurrentApplicationWindowOrientation", true);
}

void MDecoratorWindow::setWindowTitle(const QString& title)
{
    navigationBar->setViewMenuDescription(title);
}

MDecoratorWindow::~MDecoratorWindow()
{
}

bool MDecoratorWindow::x11Event(XEvent *e)
{
    Atom actual;
    int format, result;
    unsigned long n, left;
    unsigned char *data = 0;
    if (e->type == PropertyNotify
        && ((XPropertyEvent*)e)->atom == onlyStatusbarAtom) {
        result = XGetWindowProperty(QX11Info::display(), winId(),
                                    onlyStatusbarAtom, 0, 1, False,
                                    XA_CARDINAL, &actual, &format,
                                    &n, &left, &data);
        if (result == Success && data) {
            bool val = *((long*)data);
            if (val != only_statusbar)
                d->RemoteSetOnlyStatusbar(val);
        }
        if (data)
            XFree(data);
        return true;
    } else if (e->type == PropertyNotify
               && ((XPropertyEvent*)e)->atom == managedWindowAtom) {
        result = XGetWindowProperty(QX11Info::display(), winId(),
                                    managedWindowAtom, 0, 1, False,
                                    XA_WINDOW, &actual, &format,
                                    &n, &left, &data);
        if (result == Success && data)
            d->RemoteSetManagedWinId(*((long*)data));
        if (data)
            XFree(data);
        return true;
    }
    return false;
}

void MDecoratorWindow::setOnlyStatusbar(bool mode)
{
    if (mode) {
        sceneManager()->disappearSceneWindowNow(navigationBar);
        sceneManager()->disappearSceneWindowNow(homeButtonPanel);
        sceneManager()->disappearSceneWindowNow(escapeButtonPanel);
    } else {
        sceneManager()->appearSceneWindowNow(navigationBar);
        sceneManager()->appearSceneWindowNow(homeButtonPanel);
        sceneManager()->appearSceneWindowNow(escapeButtonPanel);
    }
    only_statusbar = mode;
}

void MDecoratorWindow::screenRotated(const M::Orientation &orientation)
{
    Q_UNUSED(orientation);
    setInputRegion();
    d->setAvailableGeometry(availableClientRect());
}

XRectangle MDecoratorWindow::itemRectToScreenRect(const QRect& r)
{
    XRectangle rect;
    Display *dpy = QX11Info::display();
    int xres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->width;
    int yres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->height;
    switch (sceneManager()->orientationAngle()) {
    case 0:
            rect.x = r.x();
            rect.y = r.y();
            rect.width = r.width();
            rect.height = r.height();
            break;
    case 90:
            rect.x = xres - r.height();
            rect.y = 0;
            rect.width = r.height();
            rect.height = r.width();
            break;
    case 270:
            rect.x = rect.y = 0;
            rect.width = r.height();
            rect.height = r.width();
            break;
    case 180:
            rect.x = 0;
            rect.y = yres - r.height();
            rect.width = r.width();
            rect.height = r.height();
            break;
    default:
            memset(&rect, 0, sizeof(rect));
            break;
    }
    return rect;
}

void MDecoratorWindow::setInputRegion()
{
    static XRectangle prev_rect = {0, 0, 0, 0};
    QRegion region;
    QRect r_tmp(statusBar->geometry().toRect());
    region += statusBar->mapToScene(r_tmp).boundingRect().toRect();
    if (!only_statusbar) {
        r_tmp = QRect(navigationBar->geometry().toRect());
        region += navigationBar->mapToScene(r_tmp).boundingRect().toRect();
        r_tmp = QRect(homeButtonPanel->geometry().toRect());
        region += homeButtonPanel->mapToScene(r_tmp).boundingRect().toRect();
        r_tmp = QRect(escapeButtonPanel->geometry().toRect());
        region += escapeButtonPanel->mapToScene(r_tmp).boundingRect().toRect();
    }

    const QRect fs(QApplication::desktop()->screenGeometry());
    decoratorRect = region.boundingRect();
    // crop it to fullscreen to work around a weird issue
    if (decoratorRect.width() > fs.width())
        decoratorRect.setWidth(fs.width());
    if (decoratorRect.height() > fs.height())
        decoratorRect.setHeight(fs.height());

    if (!only_statusbar && decoratorRect.width() > fs.width() / 2
        && decoratorRect.height() > fs.height() / 2) {
        // decorator is so big that it is probably in more than one part
        // (which is not yet supported)
        setOnlyStatusbar(true);
        region = decoratorRect = statusBar->geometry().toRect();
    }
    XRectangle rect = itemRectToScreenRect(decoratorRect);
    if (memcmp(&prev_rect, &rect, sizeof(XRectangle))) {
        Display *dpy = QX11Info::display();
        XserverRegion shapeRegion = XFixesCreateRegion(dpy, &rect, 1);
        XShapeCombineRectangles(dpy, winId(), ShapeBounding, 0, 0, &rect, 1,
                            ShapeSet, Unsorted);
        XFixesSetWindowShapeRegion(dpy, winId(), ShapeInput, 0, 0, shapeRegion);
        XFixesDestroyRegion(dpy, shapeRegion);
        XSync(dpy, False);
        prev_rect = rect;
    }

    // selective compositing
    if (isVisible() && region.isEmpty()) {
        hide();
    } else if (!isVisible() && !region.isEmpty()) {
        show();
    }
}

void MDecoratorWindow::setSceneSize()
{
    // always keep landscape size
    Display *dpy = QX11Info::display();
    int xres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->width;
    int yres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->height;
    scene()->setSceneRect(0, 0, xres, yres);
    setMinimumSize(xres, yres);
    setMaximumSize(xres, yres);
}

void MDecoratorWindow::setMDecoratorWindowProperty()
{

    long on = 1;

    XChangeProperty(QX11Info::display(), winId(),
                    XInternAtom(QX11Info::display(), "_MEEGOTOUCH_DECORATOR_WINDOW", False),
                    XA_CARDINAL,
                    32, PropModeReplace,
                    (unsigned char *) &on, 1);
}

const QRect MDecoratorWindow::availableClientRect() const
{
    return decoratorRect;
}

void MDecoratorWindow::closeEvent(QCloseEvent * event )
{
    // never close the decorator!
    return event->ignore();
}

#include "mdecoratorwindow.moc"
<commit_msg>set right decoratorRect in case it's too large<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of duicompositor.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QtDebug>

#include <MSceneManager>
#include <MScene>

#include <QApplication>
#include <QDesktopWidget>
#include <QX11Info>
#include <QGLFormat>
#include <QGLWidget>

#include "mdecoratorwindow.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xmd.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>

#include <mabstractdecorator.h>

class MDecorator: public MAbstractDecorator
{
    Q_OBJECT
public:
    MDecorator(MDecoratorWindow *p)
        : MAbstractDecorator(p),
        decorwindow(p)
    {
    }

    ~MDecorator() {
    }

    virtual void manageEvent(Qt::HANDLE window)
    {
        XTextProperty p;
        QString title;

        if(XGetWMName(QX11Info::display(), window, &p)) {
            if (p.value) {
                title = (char*) p.value;
                XFree(p.value);
            }
        }
        decorwindow->setInputRegion();
        setAvailableGeometry(decorwindow->availableClientRect());
        decorwindow->setWindowTitle(title);
    }

protected:
    virtual void activateEvent() {
    }

    virtual void setAutoRotation(bool mode)
    {
        Q_UNUSED(mode)
        // we follow the orientation of the topmost app
    }

    virtual void setOnlyStatusbar(bool mode)
    {
        decorwindow->setOnlyStatusbar(mode);
        decorwindow->setInputRegion();
        setAvailableGeometry(decorwindow->availableClientRect());
    }

private:

    MDecoratorWindow *decorwindow;
};

#if 0
static QRect windowRectFromGraphicsItem(const QGraphicsView &view,
                                        const QGraphicsItem &item)
{
    return view.mapFromScene(
               item.mapToScene(
                   item.boundingRect()
               )
           ).boundingRect();
}
#endif

MDecoratorWindow::MDecoratorWindow(QWidget *parent)
    : MWindow(parent)
{
    onlyStatusbarAtom = XInternAtom(QX11Info::display(),
                                    "_MDECORATOR_ONLY_STATUSBAR", False);
    managedWindowAtom = XInternAtom(QX11Info::display(),
                                    "_MDECORATOR_MANAGED_WINDOW", False);

    homeButtonPanel = new MHomeButtonPanel();
    escapeButtonPanel = new MEscapeButtonPanel();
    navigationBar = new MNavigationBar();
    statusBar = new MStatusBar();

    connect(homeButtonPanel, SIGNAL(buttonClicked()), this,
            SIGNAL(homeClicked()));
    connect(escapeButtonPanel, SIGNAL(buttonClicked()), this,
            SIGNAL(escapeClicked()));

    sceneManager()->appearSceneWindowNow(statusBar);
    setOnlyStatusbar(false);

    d = new MDecorator(this);
    connect(this, SIGNAL(homeClicked()), d, SLOT(minimize()));
    connect(this, SIGNAL(escapeClicked()), d, SLOT(close()));
    connect(sceneManager(),
            SIGNAL(orientationChanged(M::Orientation)),
            this,
            SLOT(screenRotated(M::Orientation)));

    setFocusPolicy(Qt::NoFocus);
    setSceneSize();
    setMDecoratorWindowProperty();

    setInputRegion();
    setProperty("followsCurrentApplicationWindowOrientation", true);
}

void MDecoratorWindow::setWindowTitle(const QString& title)
{
    navigationBar->setViewMenuDescription(title);
}

MDecoratorWindow::~MDecoratorWindow()
{
}

bool MDecoratorWindow::x11Event(XEvent *e)
{
    Atom actual;
    int format, result;
    unsigned long n, left;
    unsigned char *data = 0;
    if (e->type == PropertyNotify
        && ((XPropertyEvent*)e)->atom == onlyStatusbarAtom) {
        result = XGetWindowProperty(QX11Info::display(), winId(),
                                    onlyStatusbarAtom, 0, 1, False,
                                    XA_CARDINAL, &actual, &format,
                                    &n, &left, &data);
        if (result == Success && data) {
            bool val = *((long*)data);
            if (val != only_statusbar)
                d->RemoteSetOnlyStatusbar(val);
        }
        if (data)
            XFree(data);
        return true;
    } else if (e->type == PropertyNotify
               && ((XPropertyEvent*)e)->atom == managedWindowAtom) {
        result = XGetWindowProperty(QX11Info::display(), winId(),
                                    managedWindowAtom, 0, 1, False,
                                    XA_WINDOW, &actual, &format,
                                    &n, &left, &data);
        if (result == Success && data)
            d->RemoteSetManagedWinId(*((long*)data));
        if (data)
            XFree(data);
        return true;
    }
    return false;
}

void MDecoratorWindow::setOnlyStatusbar(bool mode)
{
    if (mode) {
        sceneManager()->disappearSceneWindowNow(navigationBar);
        sceneManager()->disappearSceneWindowNow(homeButtonPanel);
        sceneManager()->disappearSceneWindowNow(escapeButtonPanel);
    } else {
        sceneManager()->appearSceneWindowNow(navigationBar);
        sceneManager()->appearSceneWindowNow(homeButtonPanel);
        sceneManager()->appearSceneWindowNow(escapeButtonPanel);
    }
    only_statusbar = mode;
}

void MDecoratorWindow::screenRotated(const M::Orientation &orientation)
{
    Q_UNUSED(orientation);
    setInputRegion();
    d->setAvailableGeometry(availableClientRect());
}

XRectangle MDecoratorWindow::itemRectToScreenRect(const QRect& r)
{
    XRectangle rect;
    Display *dpy = QX11Info::display();
    int xres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->width;
    int yres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->height;
    switch (sceneManager()->orientationAngle()) {
    case 0:
            rect.x = r.x();
            rect.y = r.y();
            rect.width = r.width();
            rect.height = r.height();
            break;
    case 90:
            rect.x = xres - r.height();
            rect.y = 0;
            rect.width = r.height();
            rect.height = r.width();
            break;
    case 270:
            rect.x = rect.y = 0;
            rect.width = r.height();
            rect.height = r.width();
            break;
    case 180:
            rect.x = 0;
            rect.y = yres - r.height();
            rect.width = r.width();
            rect.height = r.height();
            break;
    default:
            memset(&rect, 0, sizeof(rect));
            break;
    }
    return rect;
}

void MDecoratorWindow::setInputRegion()
{
    static XRectangle prev_rect = {0, 0, 0, 0};
    QRegion region;
    QRect r_tmp(statusBar->geometry().toRect());
    region += statusBar->mapToScene(r_tmp).boundingRect().toRect();
    if (!only_statusbar) {
        r_tmp = QRect(navigationBar->geometry().toRect());
        region += navigationBar->mapToScene(r_tmp).boundingRect().toRect();
        r_tmp = QRect(homeButtonPanel->geometry().toRect());
        region += homeButtonPanel->mapToScene(r_tmp).boundingRect().toRect();
        r_tmp = QRect(escapeButtonPanel->geometry().toRect());
        region += escapeButtonPanel->mapToScene(r_tmp).boundingRect().toRect();
    }

    const QRect fs(QApplication::desktop()->screenGeometry());
    decoratorRect = region.boundingRect();
    // crop it to fullscreen to work around a weird issue
    if (decoratorRect.width() > fs.width())
        decoratorRect.setWidth(fs.width());
    if (decoratorRect.height() > fs.height())
        decoratorRect.setHeight(fs.height());

    if (!only_statusbar && decoratorRect.width() > fs.width() / 2
        && decoratorRect.height() > fs.height() / 2) {
        // decorator is so big that it is probably in more than one part
        // (which is not yet supported)
        setOnlyStatusbar(true);
        r_tmp = statusBar->geometry().toRect();
        region = decoratorRect = statusBar->mapToScene(r_tmp).boundingRect().toRect();
    }
    XRectangle rect = itemRectToScreenRect(decoratorRect);
    if (memcmp(&prev_rect, &rect, sizeof(XRectangle))) {
        Display *dpy = QX11Info::display();
        XserverRegion shapeRegion = XFixesCreateRegion(dpy, &rect, 1);
        XShapeCombineRectangles(dpy, winId(), ShapeBounding, 0, 0, &rect, 1,
                            ShapeSet, Unsorted);
        XFixesSetWindowShapeRegion(dpy, winId(), ShapeInput, 0, 0, shapeRegion);
        XFixesDestroyRegion(dpy, shapeRegion);
        XSync(dpy, False);
        prev_rect = rect;
    }

    // selective compositing
    if (isVisible() && region.isEmpty()) {
        hide();
    } else if (!isVisible() && !region.isEmpty()) {
        show();
    }
}

void MDecoratorWindow::setSceneSize()
{
    // always keep landscape size
    Display *dpy = QX11Info::display();
    int xres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->width;
    int yres = ScreenOfDisplay(dpy, DefaultScreen(dpy))->height;
    scene()->setSceneRect(0, 0, xres, yres);
    setMinimumSize(xres, yres);
    setMaximumSize(xres, yres);
}

void MDecoratorWindow::setMDecoratorWindowProperty()
{

    long on = 1;

    XChangeProperty(QX11Info::display(), winId(),
                    XInternAtom(QX11Info::display(), "_MEEGOTOUCH_DECORATOR_WINDOW", False),
                    XA_CARDINAL,
                    32, PropModeReplace,
                    (unsigned char *) &on, 1);
}

const QRect MDecoratorWindow::availableClientRect() const
{
    return decoratorRect;
}

void MDecoratorWindow::closeEvent(QCloseEvent * event )
{
    // never close the decorator!
    return event->ignore();
}

#include "mdecoratorwindow.moc"
<|endoftext|>


<commit_before>#include "Animation_Seasonal.hpp"

/* ~~~ Animation Seasonal Spring: Clear Sky Blue Color Fade */

Animation_Seasonal_Spring_ClearSkyFade::Animation_Seasonal_Spring_ClearSkyFade(Adafruit_NeoPixel* strip) {
	this->strip = strip;
}

void Animation_Seasonal_Spring_ClearSkyFade::init() {
 	Animation_Seasonal::init();
	this->name = getNameOfStrip(this->strip);
 	this->name += F(": Clear Skies");
	this->num_strips = 1;
	this->update_rate = 50;
	this->strips = getAsStripArray(this->strip);

	this->stack = new LocalStack();
	this->stack->push(new MemObj(new unsigned int(0)));
	this->stack->push(new MemObj(new bool(true)));
	this->stack->push(new MemObj(new unsigned short int(0)));
	this->stack->push(new MemObj(new unsigned short int(0)));
}

void Animation_Seasonal_Spring_ClearSkyFade::step() {
	static const int MAX_RED = 200;
	static const int MAX_GREEN = 180;
	static const int BLUE = 255;

	unsigned int& i = this->stack->get(0)->get<unsigned int>();
	bool& increasing = this->stack->get(1)->get<bool>();
	unsigned short int& red = this->stack->get(2)->get<unsigned short int>();
	unsigned short int& green = this->stack->get(3)->get<unsigned short int>();

	// step animation
	for (unsigned int x = 0; x < this->strip->numPixels(); x++) {
		this->strip->setPixelColor(x, MAX_RED - i, MAX_GREEN - i, BLUE);
	}

	if (increasing) {
		if (i >= 50) {
			i--;
			increasing = false;
		} else {
			i++;
		}
	} else {
		if (i <= 0) {
			i++;
			increasing = true;
      		this->current_exec++;
		} else {
			i--;
		}
	}

}

void Animation_Seasonal_Spring_ClearSkyFade::clean() {
	this->stack->get(0)->destroy<unsigned int>();
	this->stack->get(1)->destroy<bool>();
	this->stack->get(2)->destroy<unsigned short int>();
	this->stack->get(3)->destroy<unsigned short int>();

	delete this->stack;
}
<commit_msg>show() helps things actually work<commit_after>#include "Animation_Seasonal.hpp"

/* ~~~ Animation Seasonal Spring: Clear Sky Blue Color Fade */

Animation_Seasonal_Spring_ClearSkyFade::Animation_Seasonal_Spring_ClearSkyFade(Adafruit_NeoPixel* strip) {
	this->strip = strip;
}

void Animation_Seasonal_Spring_ClearSkyFade::init() {
 	Animation_Seasonal::init();
	this->name = getNameOfStrip(this->strip);
 	this->name += F(": Clear Skies");
	this->num_strips = 1;
	this->update_rate = 50;
	this->strips = getAsStripArray(this->strip);

	this->stack = new LocalStack();
	this->stack->push(new MemObj(new unsigned int(0)));
	this->stack->push(new MemObj(new bool(true)));
	this->stack->push(new MemObj(new unsigned short int(0)));
	this->stack->push(new MemObj(new unsigned short int(0)));
}

void Animation_Seasonal_Spring_ClearSkyFade::step() {
	static const int MAX_RED = 200;
	static const int MAX_GREEN = 180;
	static const int BLUE = 255;

	unsigned int& i = this->stack->get(0)->get<unsigned int>();
	bool& increasing = this->stack->get(1)->get<bool>();

	// step animation
	for (unsigned int x = 0; x < this->strip->numPixels(); x++) {
		this->strip->setPixelColor(x, MAX_RED - i, MAX_GREEN - i, BLUE);
	}

	this->strip->show();

	if (increasing) {
		if (i >= 150) {
			i--;
			increasing = false;
		} else {
			i++;
		}
	} else {
		if (i <= 0) {
			i++;
			increasing = true;
      		this->current_exec++;
		} else {
			i--;
		}
	}

}

void Animation_Seasonal_Spring_ClearSkyFade::clean() {
	this->stack->get(0)->destroy<unsigned int>();
	this->stack->get(1)->destroy<bool>();
	this->stack->get(2)->destroy<unsigned short int>();
	this->stack->get(3)->destroy<unsigned short int>();

	delete this->stack;
}
<|endoftext|>


<commit_before>/*
 * filter_rbpitch.c -- adjust audio pitch
 * Copyright (C) 2020 Meltytech, LLC
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <framework/mlt.h>
#include <framework/mlt_log.h>

#include <rubberband/RubberBandStretcher.h>

#include <algorithm>
#include <cstring>
#include <math.h>

using namespace RubberBand;

// Private Types
typedef struct
{
	RubberBandStretcher* s;
	int rubberband_frequency;
	uint64_t in_samples;
	uint64_t out_samples;
} private_data;

static const size_t MAX_CHANNELS = 10;

static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	mlt_filter filter = static_cast<mlt_filter>(mlt_frame_pop_audio( frame ));
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
	private_data* pdata = (private_data*)filter->child;
	if ( *channels > (int)MAX_CHANNELS )
	{
		mlt_log_error( MLT_FILTER_SERVICE(filter), "Too many channels requested: %d > %d\n", *channels, (int)MAX_CHANNELS );
		return mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	}

	int requested_samples = *samples;
	mlt_properties unique_properties = mlt_frame_get_unique_properties( frame, MLT_FILTER_SERVICE(filter) );
	if ( !unique_properties )
	{
		mlt_log_error( MLT_FILTER_SERVICE(filter), "Missing unique_properites\n" );
		return mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	}

	// Get the producer's audio
	*format = mlt_audio_float;
	int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	if ( error ) return error;

	// Make sure the audio is in the correct format
	// This is useful if the filter is encapsulated in a producer and does not
	// have a normalizing filter before it.
	if (*format != mlt_audio_float && frame->convert_audio != NULL)
	{
		frame->convert_audio( frame, buffer, format, mlt_audio_float );
	}

	// Sanity check parameters
	// rubberband library crashes have been seen with a very large scale factor
	// or very small sampling frequency. Very small scale factor and very high
	// sampling frequency can result in too much audio lag.
	// Disallow these extreme scenarios for now. Maybe it will be improved in
	// the future.
	double pitchscale = mlt_properties_get_double( unique_properties, "pitchscale" );
	pitchscale = CLAMP( pitchscale, 0.05, 50.0 );
	int rubberband_frequency = CLAMP( *frequency, 10000, 300000 );

	// Protect the RubberBandStretcher instance.
	mlt_service_lock( MLT_FILTER_SERVICE(filter) );

	// Configure the stretcher.
	RubberBandStretcher* s = pdata->s;
	if ( !s || s->available() == -1 || (int)s->getChannelCount() != *channels || pdata->rubberband_frequency != rubberband_frequency )
	{
		mlt_log_debug( MLT_FILTER_SERVICE(filter), "Create a new stretcher\t%d\t%d\t%f\n", *channels, rubberband_frequency, pitchscale );
		delete s;
		// Create a rubberband instance
		RubberBandStretcher::Options options = RubberBandStretcher::OptionProcessRealTime;
		s = new RubberBandStretcher(rubberband_frequency, *channels, options, 1.0, pitchscale);
		pdata->s = s;
		pdata->rubberband_frequency = rubberband_frequency;
		pdata->in_samples = 0;
		pdata->out_samples = 0;
	}
	s->setPitchScale(pitchscale);
	if( pitchscale > 0.5 && pitchscale < 2.0 )
	{
		// Pitch adjustment < 200%
		s->setPitchOption(RubberBandStretcher::OptionPitchHighQuality);
		s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
	}
	else
	{
		// Pitch adjustment > 200%
		// "HighConsistency" and "Smooth" options help to avoid large memory
		// consumption and crashes that can occur for large pitch adjustments.
		s->setPitchOption(RubberBandStretcher::OptionPitchHighConsistency);
		s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
	}

	// Configure input and output buffers and counters.
	int consumed_samples = 0;
	int total_consumed_samples = 0;
	int received_samples = 0;
	struct mlt_audio_s in;
	struct mlt_audio_s out;
	mlt_audio_set_values( &in, *buffer, *frequency, *format, *samples, *channels );
	mlt_audio_set_values( &out, NULL, *frequency, *format, *samples, *channels );
	mlt_audio_alloc_data( &out );

	// Process all input samples
	while ( true )
	{
		// Send more samples to the stretcher
		if ( consumed_samples == in.samples )
		{
			// Continue to repeat input samples into the stretcher until it
			// provides the desired number of samples out.
			consumed_samples = 0;
			mlt_log_debug( MLT_FILTER_SERVICE(filter), "Repeat samples\n");
		}
		int process_samples = std::min( in.samples - consumed_samples, (int)s->getSamplesRequired() );
		if ( process_samples == 0 && received_samples == out.samples && total_consumed_samples < in.samples )
		{
			// No more out samples are needed, but input samples are still available.
			// Send the final input samples for processing.
			process_samples = in.samples - total_consumed_samples;
		}
		if ( process_samples > 0 )
		{
			float* in_planes[MAX_CHANNELS];
			for ( int i = 0; i < in.channels; i++ )
			{
				in_planes[i] = ((float*)in.data) + (in.samples * i) + consumed_samples;
			}
			s->process( in_planes, process_samples, false );
			consumed_samples += process_samples;
			total_consumed_samples += process_samples;
			pdata->in_samples += process_samples;
		}

		// Receive samples from the stretcher
		int retrieve_samples = std::min( out.samples - received_samples, s->available() );
		if ( retrieve_samples > 0 )
		{
			float* out_planes[MAX_CHANNELS];
			for ( int i = 0; i < out.channels; i++ )
			{
				out_planes[i] = ((float*)out.data) + (out.samples * i) + received_samples;
			}
			retrieve_samples = (int)s->retrieve( out_planes, retrieve_samples );
			received_samples += retrieve_samples;
			pdata->out_samples += retrieve_samples;
		}

		mlt_log_debug( MLT_FILTER_SERVICE(filter), "Process: %d\t Retrieve: %d\n", process_samples, retrieve_samples );

		if ( received_samples == out.samples && total_consumed_samples >= in.samples )
		{
			// There is nothing more to do;
			break;
		}
	}

	// Save the processed samples.
	mlt_audio_shrink( &out, received_samples );
	mlt_frame_set_audio( frame, out.data, out.format, 0, out.release_data );
	mlt_audio_get_values( &out, buffer, frequency, format, samples, channels );

	// Report the latency.
	double latency = (double)(pdata->in_samples - pdata->out_samples) * 1000.0 / (double)*frequency;
	mlt_properties_set_double( filter_properties, "latency", latency );

	mlt_service_unlock( MLT_FILTER_SERVICE(filter) );

	mlt_log_debug( MLT_FILTER_SERVICE(filter), "Requested: %d\tReceived: %d\tSent: %d\tLatency: %d(%fms)\n", requested_samples, in.samples, out.samples, (int)(pdata->in_samples - pdata->out_samples), latency );
	return error;
}

static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
{
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
	mlt_position position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );

	// Determine the pitchscale
	double pitchscale = 1.0;
	if ( mlt_properties_exists( filter_properties, "pitchscale" ) )
	{
		pitchscale = mlt_properties_anim_get_double( filter_properties, "pitchscale", position, length );
	}
	else
	{
		double octaveshift = mlt_properties_anim_get_double( filter_properties, "octaveshift", position, length );
		pitchscale = pow(2, octaveshift);
	}
	if ( pitchscale <= 0.0 || /*check for nan:*/pitchscale != pitchscale )
	{
		pitchscale = 1.0;
	}

	// Save the pitchscale on the frame to be used in rbpitch_get_audio
	mlt_properties unique_properties = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE(filter) );
	mlt_properties_set_double( unique_properties, "pitchscale", pitchscale );

	mlt_frame_push_audio( frame, (void*)filter );
	mlt_frame_push_audio( frame, (void*)rbpitch_get_audio );

	return frame;
}

static void close_filter( mlt_filter filter )
{
	private_data* pdata = (private_data*)filter->child;
	if ( pdata )
	{
		RubberBandStretcher* s = static_cast<RubberBandStretcher*>(pdata->s);
		if ( s )
		{
			delete s;
		}
		free( pdata );
		filter->child = NULL;
	}
}

extern "C" {

mlt_filter filter_rbpitch_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
	mlt_filter filter = mlt_filter_new();
	private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) );

	if( filter && pdata )
	{
		pdata->s = NULL;
		pdata->rubberband_frequency = 0;
		pdata->in_samples = 0;
		pdata->out_samples = 0;

		filter->process = filter_process;
		filter->close = close_filter;
		filter->child = pdata;
	}
	else
	{
		mlt_log_error( MLT_FILTER_SERVICE(filter), "Failed to initialize\n" );

		if( filter )
		{
			mlt_filter_close( filter );
		}

		if( pdata )
		{
			free( pdata );
		}

		filter = NULL;
	}
	return filter;
}

}
<commit_msg>Include 0.5 and 2.0 in higher quality transient setting<commit_after>/*
 * filter_rbpitch.c -- adjust audio pitch
 * Copyright (C) 2020 Meltytech, LLC
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <framework/mlt.h>
#include <framework/mlt_log.h>

#include <rubberband/RubberBandStretcher.h>

#include <algorithm>
#include <cstring>
#include <math.h>

using namespace RubberBand;

// Private Types
typedef struct
{
	RubberBandStretcher* s;
	int rubberband_frequency;
	uint64_t in_samples;
	uint64_t out_samples;
} private_data;

static const size_t MAX_CHANNELS = 10;

static int rbpitch_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
	mlt_filter filter = static_cast<mlt_filter>(mlt_frame_pop_audio( frame ));
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
	private_data* pdata = (private_data*)filter->child;
	if ( *channels > (int)MAX_CHANNELS )
	{
		mlt_log_error( MLT_FILTER_SERVICE(filter), "Too many channels requested: %d > %d\n", *channels, (int)MAX_CHANNELS );
		return mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	}

	int requested_samples = *samples;
	mlt_properties unique_properties = mlt_frame_get_unique_properties( frame, MLT_FILTER_SERVICE(filter) );
	if ( !unique_properties )
	{
		mlt_log_error( MLT_FILTER_SERVICE(filter), "Missing unique_properites\n" );
		return mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	}

	// Get the producer's audio
	*format = mlt_audio_float;
	int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
	if ( error ) return error;

	// Make sure the audio is in the correct format
	// This is useful if the filter is encapsulated in a producer and does not
	// have a normalizing filter before it.
	if (*format != mlt_audio_float && frame->convert_audio != NULL)
	{
		frame->convert_audio( frame, buffer, format, mlt_audio_float );
	}

	// Sanity check parameters
	// rubberband library crashes have been seen with a very large scale factor
	// or very small sampling frequency. Very small scale factor and very high
	// sampling frequency can result in too much audio lag.
	// Disallow these extreme scenarios for now. Maybe it will be improved in
	// the future.
	double pitchscale = mlt_properties_get_double( unique_properties, "pitchscale" );
	pitchscale = CLAMP( pitchscale, 0.05, 50.0 );
	int rubberband_frequency = CLAMP( *frequency, 10000, 300000 );

	// Protect the RubberBandStretcher instance.
	mlt_service_lock( MLT_FILTER_SERVICE(filter) );

	// Configure the stretcher.
	RubberBandStretcher* s = pdata->s;
	if ( !s || s->available() == -1 || (int)s->getChannelCount() != *channels || pdata->rubberband_frequency != rubberband_frequency )
	{
		mlt_log_debug( MLT_FILTER_SERVICE(filter), "Create a new stretcher\t%d\t%d\t%f\n", *channels, rubberband_frequency, pitchscale );
		delete s;
		// Create a rubberband instance
		RubberBandStretcher::Options options = RubberBandStretcher::OptionProcessRealTime;
		s = new RubberBandStretcher(rubberband_frequency, *channels, options, 1.0, pitchscale);
		pdata->s = s;
		pdata->rubberband_frequency = rubberband_frequency;
		pdata->in_samples = 0;
		pdata->out_samples = 0;
	}
	s->setPitchScale(pitchscale);
	if( pitchscale >= 0.5 && pitchscale <= 2.0 )
	{
		// Pitch adjustment < 200%
		s->setPitchOption(RubberBandStretcher::OptionPitchHighQuality);
		s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
	}
	else
	{
		// Pitch adjustment > 200%
		// "HighConsistency" and "Smooth" options help to avoid large memory
		// consumption and crashes that can occur for large pitch adjustments.
		s->setPitchOption(RubberBandStretcher::OptionPitchHighConsistency);
		s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
	}

	// Configure input and output buffers and counters.
	int consumed_samples = 0;
	int total_consumed_samples = 0;
	int received_samples = 0;
	struct mlt_audio_s in;
	struct mlt_audio_s out;
	mlt_audio_set_values( &in, *buffer, *frequency, *format, *samples, *channels );
	mlt_audio_set_values( &out, NULL, *frequency, *format, *samples, *channels );
	mlt_audio_alloc_data( &out );

	// Process all input samples
	while ( true )
	{
		// Send more samples to the stretcher
		if ( consumed_samples == in.samples )
		{
			// Continue to repeat input samples into the stretcher until it
			// provides the desired number of samples out.
			consumed_samples = 0;
			mlt_log_debug( MLT_FILTER_SERVICE(filter), "Repeat samples\n");
		}
		int process_samples = std::min( in.samples - consumed_samples, (int)s->getSamplesRequired() );
		if ( process_samples == 0 && received_samples == out.samples && total_consumed_samples < in.samples )
		{
			// No more out samples are needed, but input samples are still available.
			// Send the final input samples for processing.
			process_samples = in.samples - total_consumed_samples;
		}
		if ( process_samples > 0 )
		{
			float* in_planes[MAX_CHANNELS];
			for ( int i = 0; i < in.channels; i++ )
			{
				in_planes[i] = ((float*)in.data) + (in.samples * i) + consumed_samples;
			}
			s->process( in_planes, process_samples, false );
			consumed_samples += process_samples;
			total_consumed_samples += process_samples;
			pdata->in_samples += process_samples;
		}

		// Receive samples from the stretcher
		int retrieve_samples = std::min( out.samples - received_samples, s->available() );
		if ( retrieve_samples > 0 )
		{
			float* out_planes[MAX_CHANNELS];
			for ( int i = 0; i < out.channels; i++ )
			{
				out_planes[i] = ((float*)out.data) + (out.samples * i) + received_samples;
			}
			retrieve_samples = (int)s->retrieve( out_planes, retrieve_samples );
			received_samples += retrieve_samples;
			pdata->out_samples += retrieve_samples;
		}

		mlt_log_debug( MLT_FILTER_SERVICE(filter), "Process: %d\t Retrieve: %d\n", process_samples, retrieve_samples );

		if ( received_samples == out.samples && total_consumed_samples >= in.samples )
		{
			// There is nothing more to do;
			break;
		}
	}

	// Save the processed samples.
	mlt_audio_shrink( &out, received_samples );
	mlt_frame_set_audio( frame, out.data, out.format, 0, out.release_data );
	mlt_audio_get_values( &out, buffer, frequency, format, samples, channels );

	// Report the latency.
	double latency = (double)(pdata->in_samples - pdata->out_samples) * 1000.0 / (double)*frequency;
	mlt_properties_set_double( filter_properties, "latency", latency );

	mlt_service_unlock( MLT_FILTER_SERVICE(filter) );

	mlt_log_debug( MLT_FILTER_SERVICE(filter), "Requested: %d\tReceived: %d\tSent: %d\tLatency: %d(%fms)\n", requested_samples, in.samples, out.samples, (int)(pdata->in_samples - pdata->out_samples), latency );
	return error;
}

static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
{
	mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
	mlt_position position = mlt_filter_get_position( filter, frame );
	mlt_position length = mlt_filter_get_length2( filter, frame );

	// Determine the pitchscale
	double pitchscale = 1.0;
	if ( mlt_properties_exists( filter_properties, "pitchscale" ) )
	{
		pitchscale = mlt_properties_anim_get_double( filter_properties, "pitchscale", position, length );
	}
	else
	{
		double octaveshift = mlt_properties_anim_get_double( filter_properties, "octaveshift", position, length );
		pitchscale = pow(2, octaveshift);
	}
	if ( pitchscale <= 0.0 || /*check for nan:*/pitchscale != pitchscale )
	{
		pitchscale = 1.0;
	}

	// Save the pitchscale on the frame to be used in rbpitch_get_audio
	mlt_properties unique_properties = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE(filter) );
	mlt_properties_set_double( unique_properties, "pitchscale", pitchscale );

	mlt_frame_push_audio( frame, (void*)filter );
	mlt_frame_push_audio( frame, (void*)rbpitch_get_audio );

	return frame;
}

static void close_filter( mlt_filter filter )
{
	private_data* pdata = (private_data*)filter->child;
	if ( pdata )
	{
		RubberBandStretcher* s = static_cast<RubberBandStretcher*>(pdata->s);
		if ( s )
		{
			delete s;
		}
		free( pdata );
		filter->child = NULL;
	}
}

extern "C" {

mlt_filter filter_rbpitch_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
	mlt_filter filter = mlt_filter_new();
	private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) );

	if( filter && pdata )
	{
		pdata->s = NULL;
		pdata->rubberband_frequency = 0;
		pdata->in_samples = 0;
		pdata->out_samples = 0;

		filter->process = filter_process;
		filter->close = close_filter;
		filter->child = pdata;
	}
	else
	{
		mlt_log_error( MLT_FILTER_SERVICE(filter), "Failed to initialize\n" );

		if( filter )
		{
			mlt_filter_close( filter );
		}

		if( pdata )
		{
			free( pdata );
		}

		filter = NULL;
	}
	return filter;
}

}
<|endoftext|>