<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "GafferArnold/Private/IECoreArnoldPreview/ShaderNetworkAlgo.h"

#include "GafferOSL/OSLShader.h"

#include "IECoreArnold/ParameterAlgo.h"

#include "IECoreScene/Shader.h"
#include "IECoreScene/ShaderNetworkAlgo.h"

#include "IECore/MessageHandler.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/SplineData.h"
#include "IECore/VectorTypedData.h"

#include "boost/algorithm/string/predicate.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/unordered_map.hpp"

using namespace std;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreArnold;

namespace
{

const AtString g_catmullRomArnoldString( "catmull-rom" );
const AtString g_bezierArnoldString( "bezier" );
const AtString g_bsplineArnoldString( "bspline" );
const AtString g_linearArnoldString( "linear" );
const AtString g_outputArnoldString( "output" );
const AtString g_shaderNameArnoldString( "shadername" );
const AtString g_oslArnoldString( "osl" );
const AtString g_nameArnoldString( "name" );

template<typename Spline>
void setSplineParameter( AtNode *node, const std::string &name, const Spline &spline )
{
	typedef vector<typename Spline::XType> PositionsVector;
	typedef vector<typename Spline::YType> ValuesVector;
	typedef TypedData<PositionsVector> PositionsData;
	typedef TypedData<ValuesVector> ValuesData;

	typename PositionsData::Ptr positionsData = new PositionsData;
	typename ValuesData::Ptr valuesData = new ValuesData;

	PositionsVector &positions = positionsData->writable();
	ValuesVector &values = valuesData->writable();
	positions.reserve( spline.points.size() );
	values.reserve( spline.points.size() );

	for( typename Spline::PointContainer::const_iterator it = spline.points.begin(), eIt = spline.points.end(); it != eIt; ++it )
	{
		positions.push_back( it->first );
		values.push_back( it->second );
	}

	AtString basis( g_catmullRomArnoldString );
	if( spline.basis == Spline::Basis::bezier() )
	{
		basis = g_bezierArnoldString;
	}
	else if( spline.basis == Spline::Basis::bSpline() )
	{
		basis = g_bsplineArnoldString;
	}
	else if( spline.basis == Spline::Basis::linear() )
	{
		basis = g_linearArnoldString;
	}

	GafferOSL::OSLShader::prepareSplineCVsForOSL( positions, values, basis );
	ParameterAlgo::setParameter( node, ( name + "Positions" ).c_str(), positionsData.get() );
	ParameterAlgo::setParameter( node, ( name + "Values" ).c_str(), valuesData.get() );
	AiNodeSetStr( node, AtString( ( name + "Basis" ).c_str() ), basis );
}

typedef boost::unordered_map<ShaderNetwork::Parameter, AtNode *> ShaderMap;

// Equivalent to Python's `s.partition( c )[0]`.
InternedString partitionStart( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return s;
	}
	else
	{
		return InternedString( s.c_str(), index );
	}
}

// Equivalent to Python's `s.partition( c )[2]`.
InternedString partitionEnd( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return InternedString();
	}
	else
	{
		return InternedString( s.c_str() + index + 1 );
	}
}

template<typename NodeCreator>
AtNode *convertWalk( const ShaderNetwork::Parameter &outputParameter, const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const NodeCreator &nodeCreator, vector<AtNode *> &nodes, ShaderMap &converted )
{
	// Reuse previously created node if we can. OSL shaders
	// can have multiple outputs, but each Arnold shader node
	// can have only a single output, so we have to emit OSL
	// shaders multiple times, once for each distinct top-level
	// output that is used.

	const IECoreScene::Shader *shader = shaderNetwork->getShader( outputParameter.shader );
	const bool isOSLShader = boost::starts_with( shader->getType(), "osl:" );
	const InternedString oslOutput = isOSLShader ? partitionStart( outputParameter.name, '.' ) : InternedString();

	auto inserted = converted.insert( { { outputParameter.shader, oslOutput }, nullptr } );
	AtNode *&node = inserted.first->second;
	if( !inserted.second )
	{
		return node;
	}

	// Create the AtNode for this shader output

	string nodeName = name;
	if( outputParameter != shaderNetwork->getOutput() )
	{
		nodeName += ":" + outputParameter.shader.string();
	}
	if( oslOutput.string().size() )
	{
		nodeName += ":" + oslOutput.string();
	}

	if( isOSLShader )
	{
		node = nodeCreator( g_oslArnoldString, AtString( nodeName.c_str() ) );
		if( oslOutput.string().size() )
		{
			AiNodeDeclare( node, g_outputArnoldString, "constant STRING" );
			AiNodeSetStr( node, g_outputArnoldString, AtString( oslOutput.c_str() ) );
		}
		AiNodeSetStr( node, g_shaderNameArnoldString, AtString( shader->getName().c_str() ) );
	}
	else
	{
		node = nodeCreator(
			AtString( shader->getName().c_str() ),
			AtString( nodeName.c_str() )
		);
	}

	if( !node )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", boost::format( "Couldn't load shader \"%s\"" ) % shader->getName() );
		return node;
	}

	// Set the shader parameters

	for( const auto &namedParameter : shader->parameters() )
	{
		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + namedParameter.first.string();
		}
		else
		{
			parameterName = namedParameter.first.string();
		}

		if( const SplineffData *splineData = runTimeCast<const SplineffData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
		}
		else if( const SplinefColor3fData *splineData = runTimeCast<const SplinefColor3fData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
			continue;
		}
		else
		{
			ParameterAlgo::setParameter( node, AtString( parameterName.c_str() ), namedParameter.second.get() );
		}
	}

	// Recurse through input connections

	for( const auto &connection : shaderNetwork->inputConnections( outputParameter.shader ) )
	{
		AtNode *sourceNode = convertWalk( connection.source, shaderNetwork, name, nodeCreator, nodes, converted );
		if( !sourceNode )
		{
			continue;
		}

		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + connection.destination.name.string();
		}
		else
		{
			parameterName = connection.destination.name.string();
		}

		InternedString sourceName = connection.source.name;
		const IECoreScene::Shader *sourceShader = shaderNetwork->getShader( connection.source.shader );
		if( boost::starts_with( sourceShader->getType(), "osl:" ) )
		{
			sourceName = partitionEnd( sourceName, '.' );
		}

		AiNodeLinkOutput( sourceNode, sourceName.c_str(), node, parameterName.c_str() );
	}

	nodes.push_back( node );
	return node;
}

AtString g_name( "name" );

const std::vector<AtString> g_protectedLightParameters = {
	AtString( "matrix" ),
	AtString( "filters" ),
	AtString( "mesh" )
};

// Similar to `AiNodeReset()`, but avoids resetting light parameters
// which we know to be unrelated to ShaderNetwork translation.
void resetNode( AtNode *node )
{
	const AtNodeEntry *nodeEntry = AiNodeGetNodeEntry( node );
	const bool isLight = AiNodeEntryGetType( nodeEntry ) == AI_NODE_LIGHT;

	AtParamIterator *it = AiNodeEntryGetParamIterator( nodeEntry );
	while( !AiParamIteratorFinished( it ) )
	{
		const AtParamEntry *param = AiParamIteratorGetNext( it );
		const AtString name = AiParamGetName( param );

		if( name == g_name )
		{
			continue;
		}

		if(
			isLight &&
			std::find(
				g_protectedLightParameters.begin(),
				g_protectedLightParameters.end(),
				name
			) != g_protectedLightParameters.end()
		)
		{
			continue;
		}

		AiNodeResetParameter( node, name );
	}
	AiParamIteratorDestroy( it );
}

} // namespace

namespace IECoreArnoldPreview
{

namespace ShaderNetworkAlgo
{

std::vector<AtNode *> convert( const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const AtNode *parentNode )
{
	ShaderNetworkPtr networkCopy;
	if( true ) // todo : make conditional on OSL < 1.10
	{
		networkCopy = shaderNetwork->copy();
		IECoreScene::ShaderNetworkAlgo::convertOSLComponentConnections( networkCopy.get() );
		shaderNetwork = networkCopy.get();
	}

	ShaderMap converted;
	vector<AtNode *> result;
	const InternedString output = shaderNetwork->getOutput().shader;
	if( output.string().empty() )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", "Shader has no output" );
	}
	else
	{
		auto nodeCreator = [parentNode]( const AtString &nodeType, const AtString &nodeName ) {
			return AiNode( nodeType, nodeName, parentNode );
		};
		convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, result, converted );
	}
	return result;
}

bool update( std::vector<AtNode *> &nodes, const IECoreScene::ShaderNetwork *shaderNetwork )
{
	assert( nodes.size() );
	AtNode *parentNode = AiNodeGetParent( nodes.back() );
	const std::string &name = AiNodeGetName( nodes.back() );

	boost::unordered_map<AtString, AtNode *, AtStringHash> originalNodes;
	for( const auto &n : nodes )
	{
		originalNodes[AtString(AiNodeGetName(n))] = n;
	}
	std::unordered_set<AtNode *> reusedNodes;
	nodes.clear();

	auto nodeCreator = [parentNode, &originalNodes, &reusedNodes]( const AtString &nodeType, const AtString &nodeName ) {
		auto it = originalNodes.find( nodeName );
		if( it != originalNodes.end() )
		{
			if( AtString( AiNodeEntryGetName( AiNodeGetNodeEntry( it->second ) ) ) == nodeType )
			{
				// Reuse original node
				AtNode *node = it->second;
				originalNodes.erase( it );
				reusedNodes.insert( node );
				resetNode( node );
				return node;
			}
			else
			{
				// Can't reuse original node. Delete it so that we
				// can reuse the name in `AiNode()` below.
				AiNodeDestroy( it->second );
				originalNodes.erase( it );
			}
		}
		return AiNode( nodeType, nodeName, parentNode );
	};

	ShaderMap converted;
	convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, nodes, converted );

	for( const auto &n : originalNodes )
	{
		AiNodeDestroy( n.second );
	}

	return nodes.size() && reusedNodes.count( nodes.back() );
}

} // namespace ShaderNetworkAlgo

} // namespace IECoreArnoldPreview
<commit_msg>ShaderNetworkAlgo : protect lightFilter transforms<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "GafferArnold/Private/IECoreArnoldPreview/ShaderNetworkAlgo.h"

#include "GafferOSL/OSLShader.h"

#include "IECoreArnold/ParameterAlgo.h"

#include "IECoreScene/Shader.h"
#include "IECoreScene/ShaderNetworkAlgo.h"

#include "IECore/MessageHandler.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/SplineData.h"
#include "IECore/VectorTypedData.h"

#include "boost/algorithm/string/predicate.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/unordered_map.hpp"

using namespace std;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreArnold;

namespace
{

const AtString g_catmullRomArnoldString( "catmull-rom" );
const AtString g_bezierArnoldString( "bezier" );
const AtString g_bsplineArnoldString( "bspline" );
const AtString g_linearArnoldString( "linear" );
const AtString g_outputArnoldString( "output" );
const AtString g_shaderNameArnoldString( "shadername" );
const AtString g_oslArnoldString( "osl" );
const AtString g_nameArnoldString( "name" );

template<typename Spline>
void setSplineParameter( AtNode *node, const std::string &name, const Spline &spline )
{
	typedef vector<typename Spline::XType> PositionsVector;
	typedef vector<typename Spline::YType> ValuesVector;
	typedef TypedData<PositionsVector> PositionsData;
	typedef TypedData<ValuesVector> ValuesData;

	typename PositionsData::Ptr positionsData = new PositionsData;
	typename ValuesData::Ptr valuesData = new ValuesData;

	PositionsVector &positions = positionsData->writable();
	ValuesVector &values = valuesData->writable();
	positions.reserve( spline.points.size() );
	values.reserve( spline.points.size() );

	for( typename Spline::PointContainer::const_iterator it = spline.points.begin(), eIt = spline.points.end(); it != eIt; ++it )
	{
		positions.push_back( it->first );
		values.push_back( it->second );
	}

	AtString basis( g_catmullRomArnoldString );
	if( spline.basis == Spline::Basis::bezier() )
	{
		basis = g_bezierArnoldString;
	}
	else if( spline.basis == Spline::Basis::bSpline() )
	{
		basis = g_bsplineArnoldString;
	}
	else if( spline.basis == Spline::Basis::linear() )
	{
		basis = g_linearArnoldString;
	}

	GafferOSL::OSLShader::prepareSplineCVsForOSL( positions, values, basis );
	ParameterAlgo::setParameter( node, ( name + "Positions" ).c_str(), positionsData.get() );
	ParameterAlgo::setParameter( node, ( name + "Values" ).c_str(), valuesData.get() );
	AiNodeSetStr( node, AtString( ( name + "Basis" ).c_str() ), basis );
}

typedef boost::unordered_map<ShaderNetwork::Parameter, AtNode *> ShaderMap;

// Equivalent to Python's `s.partition( c )[0]`.
InternedString partitionStart( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return s;
	}
	else
	{
		return InternedString( s.c_str(), index );
	}
}

// Equivalent to Python's `s.partition( c )[2]`.
InternedString partitionEnd( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return InternedString();
	}
	else
	{
		return InternedString( s.c_str() + index + 1 );
	}
}

template<typename NodeCreator>
AtNode *convertWalk( const ShaderNetwork::Parameter &outputParameter, const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const NodeCreator &nodeCreator, vector<AtNode *> &nodes, ShaderMap &converted )
{
	// Reuse previously created node if we can. OSL shaders
	// can have multiple outputs, but each Arnold shader node
	// can have only a single output, so we have to emit OSL
	// shaders multiple times, once for each distinct top-level
	// output that is used.

	const IECoreScene::Shader *shader = shaderNetwork->getShader( outputParameter.shader );
	const bool isOSLShader = boost::starts_with( shader->getType(), "osl:" );
	const InternedString oslOutput = isOSLShader ? partitionStart( outputParameter.name, '.' ) : InternedString();

	auto inserted = converted.insert( { { outputParameter.shader, oslOutput }, nullptr } );
	AtNode *&node = inserted.first->second;
	if( !inserted.second )
	{
		return node;
	}

	// Create the AtNode for this shader output

	string nodeName = name;
	if( outputParameter != shaderNetwork->getOutput() )
	{
		nodeName += ":" + outputParameter.shader.string();
	}
	if( oslOutput.string().size() )
	{
		nodeName += ":" + oslOutput.string();
	}

	if( isOSLShader )
	{
		node = nodeCreator( g_oslArnoldString, AtString( nodeName.c_str() ) );
		if( oslOutput.string().size() )
		{
			AiNodeDeclare( node, g_outputArnoldString, "constant STRING" );
			AiNodeSetStr( node, g_outputArnoldString, AtString( oslOutput.c_str() ) );
		}
		AiNodeSetStr( node, g_shaderNameArnoldString, AtString( shader->getName().c_str() ) );
	}
	else
	{
		node = nodeCreator(
			AtString( shader->getName().c_str() ),
			AtString( nodeName.c_str() )
		);
	}

	if( !node )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", boost::format( "Couldn't load shader \"%s\"" ) % shader->getName() );
		return node;
	}

	// Set the shader parameters

	for( const auto &namedParameter : shader->parameters() )
	{
		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + namedParameter.first.string();
		}
		else
		{
			parameterName = namedParameter.first.string();
		}

		if( const SplineffData *splineData = runTimeCast<const SplineffData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
		}
		else if( const SplinefColor3fData *splineData = runTimeCast<const SplinefColor3fData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
			continue;
		}
		else
		{
			ParameterAlgo::setParameter( node, AtString( parameterName.c_str() ), namedParameter.second.get() );
		}
	}

	// Recurse through input connections

	for( const auto &connection : shaderNetwork->inputConnections( outputParameter.shader ) )
	{
		AtNode *sourceNode = convertWalk( connection.source, shaderNetwork, name, nodeCreator, nodes, converted );
		if( !sourceNode )
		{
			continue;
		}

		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + connection.destination.name.string();
		}
		else
		{
			parameterName = connection.destination.name.string();
		}

		InternedString sourceName = connection.source.name;
		const IECoreScene::Shader *sourceShader = shaderNetwork->getShader( connection.source.shader );
		if( boost::starts_with( sourceShader->getType(), "osl:" ) )
		{
			sourceName = partitionEnd( sourceName, '.' );
		}

		AiNodeLinkOutput( sourceNode, sourceName.c_str(), node, parameterName.c_str() );
	}

	nodes.push_back( node );
	return node;
}

AtString g_name( "name" );
AtString g_lightBlockerNodeEntryName( "light_blocker" );

const std::vector<AtString> g_protectedLightParameters = {
	AtString( "matrix" ),
	AtString( "filters" ),
	AtString( "mesh" )
};

const std::vector<AtString> g_protectedLightFilterParameters = {
	AtString( "geometry_matrix" ),
};

// Similar to `AiNodeReset()`, but avoids resetting light parameters
// which we know to be unrelated to ShaderNetwork translation.
void resetNode( AtNode *node )
{
	const AtNodeEntry *nodeEntry = AiNodeGetNodeEntry( node );
	const bool isLight = AiNodeEntryGetType( nodeEntry ) == AI_NODE_LIGHT;
	const bool isShader = AiNodeEntryGetType( nodeEntry ) == AI_NODE_SHADER;
	const bool isLightFilter = isShader && AtString( AiNodeEntryGetName( nodeEntry ) ) == g_lightBlockerNodeEntryName;

	AtParamIterator *it = AiNodeEntryGetParamIterator( nodeEntry );
	while( !AiParamIteratorFinished( it ) )
	{
		const AtParamEntry *param = AiParamIteratorGetNext( it );
		const AtString name = AiParamGetName( param );

		if( name == g_name )
		{
			continue;
		}

		if(
			isLight &&
			std::find(
				g_protectedLightParameters.begin(),
				g_protectedLightParameters.end(),
				name
			) != g_protectedLightParameters.end()
		)
		{
			continue;
		}

		if(
			isLightFilter &&
			std::find(
				g_protectedLightFilterParameters.begin(),
				g_protectedLightFilterParameters.end(),
				name
			) != g_protectedLightFilterParameters.end()
		)
		{
			continue;
		}

		AiNodeResetParameter( node, name );
	}
	AiParamIteratorDestroy( it );
}

} // namespace

namespace IECoreArnoldPreview
{

namespace ShaderNetworkAlgo
{

std::vector<AtNode *> convert( const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const AtNode *parentNode )
{
	ShaderNetworkPtr networkCopy;
	if( true ) // todo : make conditional on OSL < 1.10
	{
		networkCopy = shaderNetwork->copy();
		IECoreScene::ShaderNetworkAlgo::convertOSLComponentConnections( networkCopy.get() );
		shaderNetwork = networkCopy.get();
	}

	ShaderMap converted;
	vector<AtNode *> result;
	const InternedString output = shaderNetwork->getOutput().shader;
	if( output.string().empty() )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", "Shader has no output" );
	}
	else
	{
		auto nodeCreator = [parentNode]( const AtString &nodeType, const AtString &nodeName ) {
			return AiNode( nodeType, nodeName, parentNode );
		};
		convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, result, converted );
	}
	return result;
}

bool update( std::vector<AtNode *> &nodes, const IECoreScene::ShaderNetwork *shaderNetwork )
{
	assert( nodes.size() );
	AtNode *parentNode = AiNodeGetParent( nodes.back() );
	const std::string &name = AiNodeGetName( nodes.back() );

	boost::unordered_map<AtString, AtNode *, AtStringHash> originalNodes;
	for( const auto &n : nodes )
	{
		originalNodes[AtString(AiNodeGetName(n))] = n;
	}
	std::unordered_set<AtNode *> reusedNodes;
	nodes.clear();

	auto nodeCreator = [parentNode, &originalNodes, &reusedNodes]( const AtString &nodeType, const AtString &nodeName ) {
		auto it = originalNodes.find( nodeName );
		if( it != originalNodes.end() )
		{
			if( AtString( AiNodeEntryGetName( AiNodeGetNodeEntry( it->second ) ) ) == nodeType )
			{
				// Reuse original node
				AtNode *node = it->second;
				originalNodes.erase( it );
				reusedNodes.insert( node );
				resetNode( node );
				return node;
			}
			else
			{
				// Can't reuse original node. Delete it so that we
				// can reuse the name in `AiNode()` below.
				AiNodeDestroy( it->second );
				originalNodes.erase( it );
			}
		}
		return AiNode( nodeType, nodeName, parentNode );
	};

	ShaderMap converted;
	convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, nodes, converted );

	for( const auto &n : originalNodes )
	{
		AiNodeDestroy( n.second );
	}

	return nodes.size() && reusedNodes.count( nodes.back() );
}

} // namespace ShaderNetworkAlgo

} // namespace IECoreArnoldPreview
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 "ioapic.hpp"
#include <hw/ioport.hpp>
#include <cstdio>
#include <cassert>
#include <debug>
#include <info>

// I/O APIC registers
#define IOAPIC_ID    0
#define IOAPIC_VER   1
#define IOAPIC_ARB   2
#define IOAPIC_RDT   3

#define IOAPIC_INTR  0x10

namespace x86
{
  struct ioapic
  {
    uint32_t read(uint8_t reg) const noexcept {
      auto volatile* addr = (uint32_t volatile*) this->base;
      addr[0] = reg;
      return addr[4];
    }
    void write(uint8_t reg, uint32_t value) {
      auto volatile* addr = (uint32_t volatile*) this->base;
      addr[0] = reg;
      addr[4] = value;
    }
    void set_entry(uint8_t index, uint32_t lo, uint32_t hi)
    {
      assert(index < entries());
      write(IOAPIC_INTR + index * 2 + 1, hi);
      write(IOAPIC_INTR + index * 2,     lo);
    }
    void set_id(uint32_t id)
    {
      write(IOAPIC_ID, id << 24);
    }

    uint8_t entries() const noexcept
    {
      return entries_;
    }

    void init(uintptr_t base)
    {
      this->base = base;
      // required: set IOAPIC ID
      set_id(0);
      // number of redirection entries supported
      entries_ = read(IOAPIC_VER) >> 16;
      entries_ = 1 + (entries_ & 0xff);

      INFO("IOAPIC", "Initializing");
      INFO2("Base addr: 0x%x  Redirection entries: %u", base, entries());

      // default: all entries disabled
      for (unsigned i = 0; i < entries(); i++)
        set_entry(i, IOAPIC_IRQ_DISABLE, 0);

      INFO("IOAPIC", "Done");
    }

    uintptr_t  base;
    uint32_t   entries_;
  };
  // there can be more than one IOAPIC
  static ioapic numbawan;

  void IOAPIC::init(const ACPI::ioapic_list& vec)
  {
    // enable IO APIC (ICMR wiring mode?)
    hw::outb(0x22, 0x70);
    hw::outb(0x23, 0x1);

    numbawan.init(vec[0].addr_base);
  }

  unsigned IOAPIC::entries()
  {
    return numbawan.entries();
  }

  void IOAPIC::set(uint8_t idx, uint32_t src, uint32_t dst)
  {
    numbawan.set_entry(idx, src, dst);
  }

  void IOAPIC::enable(uint8_t idx, uint8_t irq_dst, uint8_t dst)
  {
    uint32_t type = 0;

    if (idx > 15)
        type = (1<<15) | (1<<13);

    numbawan.set_entry(idx, type | (0x20 + irq_dst), dst);
  }
  void IOAPIC::disable(uint8_t idx)
  {
    uint32_t type = 1 << 16;

    if (idx > 15)
      type |= (1<<15) | (1<<13);

    numbawan.set_entry(idx, type | (0x20 + idx), 0x0);
  }
}
<commit_msg>x86: Update IO APIC to use struct with volatile members<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 "ioapic.hpp"
#include <hw/ioport.hpp>
#include <cstdio>
#include <cassert>
#include <debug>
#include <info>

// I/O APIC registers
#define IOAPIC_ID    0
#define IOAPIC_VER   1
#define IOAPIC_ARB   2
#define IOAPIC_RDT   3

#define IOAPIC_INTR  0x10

namespace x86
{
  struct ioapic
  {
    struct io_regs {
      volatile uint32_t reg;
      uint32_t   pad1[3];
      volatile uint32_t val;
      uint32_t   pad2[3];
    };

    uint32_t read(uint8_t reg) noexcept {
      base->reg = reg;
      return base->val;
    }
    void write(uint8_t reg, uint32_t value) noexcept {
      base->reg = reg;
      base->val = value;
    }
    void set_entry(uint8_t index, uint32_t lo, uint32_t hi)
    {
      assert(index < entries());
      write(IOAPIC_INTR + index * 2 + 1, hi);
      write(IOAPIC_INTR + index * 2,     lo);
    }
    void set_id(uint32_t id) noexcept
    {
      write(IOAPIC_ID, id << 24);
    }

    uint8_t entries() const noexcept
    {
      return entries_;
    }

    void init(uintptr_t base_addr)
    {
      INFO("IOAPIC", "Initializing");
      this->base = (decltype(base)) base_addr;
      // required: set IOAPIC ID
      set_id(0);
      // number of redirection entries supported
      auto reg = read(IOAPIC_VER) >> 16;
      this->entries_ = 1 + (reg & 0xff);

      INFO2("Base addr: %p  Redirection entries: %u", base, entries());

      // default: all entries disabled
      for (unsigned i = 0; i < entries(); i++)
        set_entry(i, IOAPIC_IRQ_DISABLE, 0);
    }

    io_regs* base;
    uint32_t entries_;
  };
  // there can be more than one IOAPIC
  static ioapic numbawan;

  void IOAPIC::init(const ACPI::ioapic_list& vec)
  {
    // enable IO APIC (ICMR wiring mode?)
    hw::outb(0x22, 0x70);
    hw::outb(0x23, 0x1);

    numbawan.init(vec[0].addr_base);
  }

  unsigned IOAPIC::entries()
  {
    return numbawan.entries();
  }

  void IOAPIC::set(uint8_t idx, uint32_t src, uint32_t dst)
  {
    numbawan.set_entry(idx, src, dst);
  }

  void IOAPIC::enable(uint8_t idx, uint8_t irq_dst, uint8_t dst)
  {
    uint32_t type = 0;

    if (idx > 15)
        type = (1<<15) | (1<<13);

    numbawan.set_entry(idx, type | (0x20 + irq_dst), dst);
  }
  void IOAPIC::disable(uint8_t idx)
  {
    uint32_t type = 1 << 16;

    if (idx > 15)
      type |= (1<<15) | (1<<13);

    numbawan.set_entry(idx, type | (0x20 + idx), 0x0);
  }
}
<|endoftext|>


<commit_before>/*
 * System_initialSync.cpp
 *
 *  Created on: Jun 25, 2014
 *      Author: Pimenta
 */

// this
#include "System.hpp"

#include "Defines.hpp"
#include "FD8Protocol.hpp"
#include "FileSystem.hpp"

using namespace std;
using namespace network;
using namespace fd8protocol;
using namespace helpers;

void System::requestSystemState() {
  // find someone to send the system state to this peer
  uint32_t ip = 0;
  for (auto& kv : users) {
    if (kv.first != localAddress.ip) {
      ip = kv.first;
      break;
    }
  }

  User& user = users[localAddress.ip];

  if (!ip) { // no one found, then return
    user.sessionID = nextSessionID++;
    return;
  }

  // ask for synchronization
  TCPConnection conn(Address(ip, Address("", TCPUDP_MAIN).port));
  conn.send(char(MTYPE_SYNC));
  user.sessionID = conn.recv<uint32_t>();
  nextSessionID = user.sessionID + 1;
  ByteQueue data(conn.recv<uint32_t>());
  conn.recv(data);
  FileSystem::deserialize(data);
}

void System::respondSystemState(TCPConnection* peer) {
  peer->send(nextSessionID);
  ByteQueue data = FileSystem::serialize();
  peer->send(uint32_t(data.size()));
  peer->send(data);
}
<commit_msg>Fixing bug<commit_after>/*
 * System_initialSync.cpp
 *
 *  Created on: Jun 25, 2014
 *      Author: Pimenta
 */

// this
#include "System.hpp"

#include "Defines.hpp"
#include "FD8Protocol.hpp"
#include "FileSystem.hpp"

using namespace std;
using namespace network;
using namespace fd8protocol;
using namespace helpers;

void System::requestSystemState() {
  // find someone to send the system state to this peer
  uint32_t ip = 0;
  for (auto& kv : users) {
    if (kv.first != localAddress.ip) {
      ip = kv.first;
      break;
    }
  }

  User& user = users[localAddress.ip];

  if (!ip) { // no one found, then return
    nextSessionID = 1;
    user.sessionID = nextSessionID++;
    return;
  }

  // ask for synchronization
  TCPConnection conn(Address(ip, Address("", TCPUDP_MAIN).port));
  conn.send(char(MTYPE_SYNC));
  user.sessionID = conn.recv<uint32_t>();
  nextSessionID = user.sessionID + 1;
  ByteQueue data(conn.recv<uint32_t>());
  conn.recv(data);
  FileSystem::deserialize(data);
}

void System::respondSystemState(TCPConnection* peer) {
  peer->send(nextSessionID);
  ByteQueue data = FileSystem::serialize();
  peer->send(uint32_t(data.size()));
  peer->send(data);
}
<|endoftext|>


<commit_before>/* CONVOLVE1 - convolution instrument

      p0 = output start time
      p1 = input start time
      p2 = input duration
      p3 = amplitude multiplier
      p4 = impulse response table (use maketable("soundfile", ...))
           must be mono; maketable lets you select channel.
      p5 = impulse start time (time to skip in table)
      p6 = impulse duration
      p7 = impulse gain
      p8 = window function table
      p9 = wet percent (0-1)
      p10 = input channel
      p11 = pan (in percent-to-left form)

   p3 (amplitude), p9 (wet percent) and p11 (pan) can receive dynamic updates
   from a table or real-time control source.

   This instrument is designed for short impulse responses: a maximum of about
   6 seconds at 44.1kHz sampling rate, though a few hundred milliseconds is more
   typical.  The impulse response duration determines the FFT size: the longer
   the response, the larger the FFT size, and therefore the more transient
   smearing.  Only one FFT of the impulse response is taken.  The FFT size of
   the input equals that of the impulse response, and there is a delay before
   the start of sound approximately equal to the impulse response duration.
   (Actually, the delay in frames is the smallest power of two that is greater
   than the impulse response length.)

   With this in mind, the best strategy for using the instrument is to loop with
   very short notes, while creeping through both the input and the impulse
   response.  See the example scores.

   NOTE: This instrument can work with very small buffer sizes (e.g., 32), but
   it probably will cause audio buffer underruns if the impulse response is
   longer than about 20 milliseconds.

   John Gibson, 5/31/05 (based on cmix convolve)
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ugens.h>
#include <Ougens.h>
#include <Instrument.h>
#include <PField.h>
#include "CONVOLVE1.h"
#include "fft.h"
#include <rt.h>
#include <rtdefs.h>

//#define DEBUG

#ifdef DEBUG
   #define DPRINT(msg)                    printf((msg))
   #define DPRINT1(msg, arg)              printf((msg), (arg))
   #define DPRINT2(msg, arg1, arg2)       printf((msg), (arg1), (arg2))
#else
   #define DPRINT(msg)
   #define DPRINT1(msg, arg)
   #define DPRINT2(msg, arg1, arg2)
#endif

const int kMinFFTsize = 256;
const int kMaxImpulseFrames = 262144;	// 2^18: about 6 seconds at 44100

inline int imax(int x, int y) { return x > y ? x : y; }
inline int imin(int x, int y) { return x < y ? x : y; }

inline float clamp(float low, float val, float high)
{
	if (val < low)
		return low;
	else if (val > high)
		return high;
	return val;
}

CONVOLVE1::CONVOLVE1() : Instrument()
{
	_inbuf = NULL;			// buffer to read (possibly multichannel) input
	_imp = NULL;			// buffer holding impulse response spectrum
	_ovadd = NULL;			// buffer for overlap-adding fft output
	_dry = NULL;			// dry signal for output
	_wet = NULL;			// wet signal for output
	_winosc = NULL;		// window function table oscillator
	_bucket = NULL;		// input bucket
	_branch = 0;
}

CONVOLVE1::~CONVOLVE1()
{
	delete [] _inbuf;
	delete [] _imp;
	delete [] _ovadd;
	delete [] _dry;
	delete [] _wet;
	delete _winosc;
	delete _bucket;
	delete _fft;
}

int CONVOLVE1::init(double p[], int n_args)
{
	const float outskip = p[0];
	const float inskip = p[1];
	const float indur = p[2];
	const float impskip = p[5];
	const float impdur = p[6];
	if (impdur <= 0.0)
		return die("CONVOLVE1", "Impulse duration must be greater than zero.");
	_impgain = p[7];
	_wetpct = p[9];	// NB: used before first call to doupdate
	if (_wetpct < 0.0 || _wetpct > 1.0)
		return die("CONVOLVE1", "Wet percent must be between 0 and 1.");
	_inchan = int(p[10]);

	// Read impulse response table, and set FFT size based on this.
	_imptab = (double *) getPFieldTable(4, &_imptablen);
	if (_imptab == NULL)
		return die("CONVOLVE1", "Must store impulse response in a table.");
	_impStartIndex = int(impskip * SR + 0.5);
	if (_impStartIndex >= _imptablen)
		return die("CONVOLVE1", "Impulse start time exceeds impulse duration.");
	int impend = _impStartIndex + int(impdur * SR + 0.5);
	// NOTE: <impend> may be past end of table; we handle that in prepareImpulse.
	DPRINT2("impend=%d, _imptablen=%d\n", impend, _imptablen);
	_impframes = impend - _impStartIndex;

	_halfFFTlen = kMinFFTsize / 2;
	for ( ; _halfFFTlen < kMaxImpulseFrames; _halfFFTlen *= 2)
		if (_halfFFTlen >= _impframes)
			break;
	_fftlen = 2 * _halfFFTlen;
	DPRINT2("_impframes=%d, _halfFFTlen=%d\n", _impframes, _halfFFTlen);
	advise("CONVOLVE1", "Using %d impulse response frames.  FFT length is %d.",
				_impframes, _fftlen);

	if (rtsetinput(inskip, this) == -1)
		return DONT_SCHEDULE;	// no input
	if (_inchan >= inputChannels())
		return die("CONVOLVE1", "You asked for channel %d of a %d-channel input.",
										_inchan, inputChannels());

	// Latency is the delay before the FFT looks at actual input rather than
	// zero-padding.  Need to let inst run long enough to compensate for this.

	const float latency = float(_impframes) / SR;
	const float ringdur = latency;
	if (rtsetoutput(outskip, latency + indur + ringdur, this) == -1)
		return DONT_SCHEDULE;
	if (outputChannels() > 2)
		return die("CONVOLVE1", "Must have mono or stereo output.");
	_inframes = int(indur * SR + 0.5);		// not including latency

	int winlen;
	double *wintab = (double *) getPFieldTable(8, &winlen);
	if (wintab) {
		if (winlen > 32767)	// limit for new fixed-point Ooscili
			return die("CONVOLVE1", "Window table size must be less than 32768.");
		const float freq = 1.0 / ((float) _impframes / SR);
		_winosc = new Ooscili(SR, freq, wintab, winlen);
	}

	return nSamps();
}

int CONVOLVE1::prepareImpulse()
{
	// copy and window impulse response; zero-pad to fft length
	const int end = imin(_imptablen, _impframes);
	if (_winosc) {
		for (int i = 0, j = _impStartIndex; i < end; i++, j++)
			_fftbuf[i] = _imptab[j] * _winosc->next(i);
	}
	else
		for (int i = 0, j = _impStartIndex; i < end; i++, j++)
			_fftbuf[i] = _imptab[j];
	for (int i = end; i < _fftlen; i++)
		_fftbuf[i] = 0.0f;

	_fft->r2c();	// take FFT

	// normalize spectrum
	double max = 0.0;
	for (int i = 0; i < _halfFFTlen; i++) {
		int index = i << 1;
		float a = _fftbuf[index];
		float b = _fftbuf[index + 1];
		double c2 = (a * a) + (b * b);
		if (c2 > max)
			max = c2;
	}
	if (max != 0.0)
		max = _impgain / sqrt(max);
	else
		return die("CONVOLVE1", "Impulse response is all zeros.");

	_imp = new float [_fftlen];
	if (_imp == NULL)
		return -1;
	for (int i = 0; i < _fftlen; i++)
		_imp[i] = _fftbuf[i] * max;

//	for (int i = 0; i < _fftlen; i++) printf("[%d] = %f\n", i, _imp[i]);

	return 0;
}

int CONVOLVE1::configure()
{
	_inbuf = new float [RTBUFSAMPS * inputChannels()];
	_ovadd = new float [_impframes];
	if (_inbuf == NULL || _ovadd == NULL)
		return -1;
	for (int i = 0; i < _impframes; i++)
		_ovadd[i] = 0.0f;

	// read index chases write index by _impframes
	_outframes = imax(_halfFFTlen, RTBUFSAMPS) * 2;
	_outReadIndex = _outframes - _impframes;
	_outWriteIndex = 0;
	_dry = new float [_outframes];
	_wet = new float [_outframes];
	if (_dry == NULL || _wet == NULL)
		return -1;
	for (int i = 0; i < _outframes; i++)
		_dry[i] = _wet[i] = 0.0f;
	DPRINT1("_outframes: %d\n", _outframes);

	_bucket = new Obucket(_impframes, processWrapper, (void *) this);
	if (_bucket == NULL)
		return -1;

	_fft = new Offt(_fftlen);
	if (_fft == NULL)
		return -1;
	_fftbuf = _fft->getbuf();

	if (prepareImpulse() != 0)
		return -1;

	return 0;
}

void CONVOLVE1::convolve()
{
	_fft->r2c();

	_fftbuf[0] = _fftbuf[0] * _imp[0];			// DC
	_fftbuf[1] = _fftbuf[1] * _imp[1];			// Nyquist

	int i = 2;
	int j = 3;
	for ( ; i < _fftlen; i += 2, j += 2) {
		float a = (_fftbuf[i] * _imp[i]) - (_fftbuf[j] * _imp[j]);
		float b = (_fftbuf[i] * _imp[j]) + (_fftbuf[j] * _imp[i]);
		_fftbuf[i] = a;
		_fftbuf[j] = b;
	}

	_fft->c2r();
}

// Called by Obucket whenever the bucket is full (i.e., has _halfFFTlen samps).
// This static member wrapper function lets us call a non-static member
// function, which we can't pass directly as a callback to Obucket.
// See http://www.newty.de/fpt/callback.html for one explanation of this.

void CONVOLVE1::processWrapper(const float buf[], const int len, void *obj)
{
	CONVOLVE1 *myself = (CONVOLVE1 *) obj;
	myself->process(buf, len);
}

void CONVOLVE1::process(const float *buf, const int len)
{
	DPRINT1("CONVOLVE1::process (len=%d)\n", len);

	// NOTE: <len> will always be equal to _impframes
	if (_winosc)
		for (int i = 0; i < len; i++)
			_fftbuf[i] = buf[i] * _winosc->next(i);
	else
		for (int i = 0; i < len; i++)
			_fftbuf[i] = buf[i];
	for (int i = len; i < _fftlen; i++)
		_fftbuf[i] = 0.0f;

	convolve();

	for (int i = 0, j = len; i < len; i++, j++) {
		_ovadd[i] += _fftbuf[i];
		_wet[_outWriteIndex] = _ovadd[i];
		_dry[_outWriteIndex] = buf[i];
		incrementOutWriteIndex();
		_ovadd[i] = _fftbuf[j];
	}

//	for (int i = 0; i < _fftlen; i++) printf("[%d] = %f\n", i, _fftbuf[i]);
}

void CONVOLVE1::doupdate()
{
	double p[12];
	update(p, 12, 1 << 3 | 1 << 9 | 1 << 11);

	_amp = p[3];
	_wetpct = clamp(0.0f, p[9], 1.0f);
	_pan = p[11];
}

int CONVOLVE1::run()
{
	const int inchans = inputChannels();
	const int outchans = outputChannels();
	const int nframes = framesToRun();

	if (currentFrame() < _inframes) {
		const int insamps = nframes * inchans;
		rtgetin(_inbuf, this, insamps);
		for (int i = _inchan; i < insamps; i += inchans)
			_bucket->drop(_inbuf[i]);
	}
	else {
		for (int i = 0; i < nframes; i++)
			_bucket->drop(0.0f);
	}
	// If in last run invocation, make sure everything in bucket is processed.
	if (currentFrame() + nframes >= nSamps())
		_bucket->flush();

	float drypct = 1.0 - _wetpct;

	for (int i = 0; i < nframes; i++) {
		if (--_branch <= 0) {
			doupdate();
			drypct = 1.0 - _wetpct;
			_branch = getSkip();
		}

		float out[2];
		out[0] = (_wet[_outReadIndex] * _wetpct) + (_dry[_outReadIndex] * drypct);
		incrementOutReadIndex();
		out[0] *= _amp;

		if (outchans == 2) {
			out[1] = out[0] * (1.0 - _pan);
			out[0] *= _pan;
		}

		rtaddout(out);
		increment();
	}

	return framesToRun();
}

Instrument *makeCONVOLVE1()
{
	CONVOLVE1 *inst;

	inst = new CONVOLVE1();
	inst->set_bus_config("CONVOLVE1");

	return inst;
}

void rtprofile()
{
	RT_INTRO("CONVOLVE1", makeCONVOLVE1);
}

<commit_msg>Remove obsolete include.<commit_after>/* CONVOLVE1 - convolution instrument

      p0 = output start time
      p1 = input start time
      p2 = input duration
      p3 = amplitude multiplier
      p4 = impulse response table (use maketable("soundfile", ...))
           must be mono; maketable lets you select channel.
      p5 = impulse start time (time to skip in table)
      p6 = impulse duration
      p7 = impulse gain
      p8 = window function table
      p9 = wet percent (0-1)
      p10 = input channel
      p11 = pan (in percent-to-left form)

   p3 (amplitude), p9 (wet percent) and p11 (pan) can receive dynamic updates
   from a table or real-time control source.

   This instrument is designed for short impulse responses: a maximum of about
   6 seconds at 44.1kHz sampling rate, though a few hundred milliseconds is more
   typical.  The impulse response duration determines the FFT size: the longer
   the response, the larger the FFT size, and therefore the more transient
   smearing.  Only one FFT of the impulse response is taken.  The FFT size of
   the input equals that of the impulse response, and there is a delay before
   the start of sound approximately equal to the impulse response duration.
   (Actually, the delay in frames is the smallest power of two that is greater
   than the impulse response length.)

   With this in mind, the best strategy for using the instrument is to loop with
   very short notes, while creeping through both the input and the impulse
   response.  See the example scores.

   NOTE: This instrument can work with very small buffer sizes (e.g., 32), but
   it probably will cause audio buffer underruns if the impulse response is
   longer than about 20 milliseconds.

   John Gibson, 5/31/05 (based on cmix convolve)
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ugens.h>
#include <Ougens.h>
#include <Instrument.h>
#include <PField.h>
#include "CONVOLVE1.h"
#include <rt.h>
#include <rtdefs.h>

//#define DEBUG

#ifdef DEBUG
   #define DPRINT(msg)                    printf((msg))
   #define DPRINT1(msg, arg)              printf((msg), (arg))
   #define DPRINT2(msg, arg1, arg2)       printf((msg), (arg1), (arg2))
#else
   #define DPRINT(msg)
   #define DPRINT1(msg, arg)
   #define DPRINT2(msg, arg1, arg2)
#endif

const int kMinFFTsize = 256;
const int kMaxImpulseFrames = 262144;	// 2^18: about 6 seconds at 44100

inline int imax(int x, int y) { return x > y ? x : y; }
inline int imin(int x, int y) { return x < y ? x : y; }

inline float clamp(float low, float val, float high)
{
	if (val < low)
		return low;
	else if (val > high)
		return high;
	return val;
}

CONVOLVE1::CONVOLVE1() : Instrument()
{
	_inbuf = NULL;			// buffer to read (possibly multichannel) input
	_imp = NULL;			// buffer holding impulse response spectrum
	_ovadd = NULL;			// buffer for overlap-adding fft output
	_dry = NULL;			// dry signal for output
	_wet = NULL;			// wet signal for output
	_winosc = NULL;		// window function table oscillator
	_bucket = NULL;		// input bucket
	_branch = 0;
}

CONVOLVE1::~CONVOLVE1()
{
	delete [] _inbuf;
	delete [] _imp;
	delete [] _ovadd;
	delete [] _dry;
	delete [] _wet;
	delete _winosc;
	delete _bucket;
	delete _fft;
}

int CONVOLVE1::init(double p[], int n_args)
{
	const float outskip = p[0];
	const float inskip = p[1];
	const float indur = p[2];
	const float impskip = p[5];
	const float impdur = p[6];
	if (impdur <= 0.0)
		return die("CONVOLVE1", "Impulse duration must be greater than zero.");
	_impgain = p[7];
	_wetpct = p[9];	// NB: used before first call to doupdate
	if (_wetpct < 0.0 || _wetpct > 1.0)
		return die("CONVOLVE1", "Wet percent must be between 0 and 1.");
	_inchan = int(p[10]);

	// Read impulse response table, and set FFT size based on this.
	_imptab = (double *) getPFieldTable(4, &_imptablen);
	if (_imptab == NULL)
		return die("CONVOLVE1", "Must store impulse response in a table.");
	_impStartIndex = int(impskip * SR + 0.5);
	if (_impStartIndex >= _imptablen)
		return die("CONVOLVE1", "Impulse start time exceeds impulse duration.");
	int impend = _impStartIndex + int(impdur * SR + 0.5);
	// NOTE: <impend> may be past end of table; we handle that in prepareImpulse.
	DPRINT2("impend=%d, _imptablen=%d\n", impend, _imptablen);
	_impframes = impend - _impStartIndex;

	_halfFFTlen = kMinFFTsize / 2;
	for ( ; _halfFFTlen < kMaxImpulseFrames; _halfFFTlen *= 2)
		if (_halfFFTlen >= _impframes)
			break;
	_fftlen = 2 * _halfFFTlen;
	DPRINT2("_impframes=%d, _halfFFTlen=%d\n", _impframes, _halfFFTlen);
	advise("CONVOLVE1", "Using %d impulse response frames.  FFT length is %d.",
				_impframes, _fftlen);

	if (rtsetinput(inskip, this) == -1)
		return DONT_SCHEDULE;	// no input
	if (_inchan >= inputChannels())
		return die("CONVOLVE1", "You asked for channel %d of a %d-channel input.",
										_inchan, inputChannels());

	// Latency is the delay before the FFT looks at actual input rather than
	// zero-padding.  Need to let inst run long enough to compensate for this.

	const float latency = float(_impframes) / SR;
	const float ringdur = latency;
	if (rtsetoutput(outskip, latency + indur + ringdur, this) == -1)
		return DONT_SCHEDULE;
	if (outputChannels() > 2)
		return die("CONVOLVE1", "Must have mono or stereo output.");
	_inframes = int(indur * SR + 0.5);		// not including latency

	int winlen;
	double *wintab = (double *) getPFieldTable(8, &winlen);
	if (wintab) {
		if (winlen > 32767)	// limit for new fixed-point Ooscili
			return die("CONVOLVE1", "Window table size must be less than 32768.");
		const float freq = 1.0 / ((float) _impframes / SR);
		_winosc = new Ooscili(SR, freq, wintab, winlen);
	}

	return nSamps();
}

int CONVOLVE1::prepareImpulse()
{
	// copy and window impulse response; zero-pad to fft length
	const int end = imin(_imptablen, _impframes);
	if (_winosc) {
		for (int i = 0, j = _impStartIndex; i < end; i++, j++)
			_fftbuf[i] = _imptab[j] * _winosc->next(i);
	}
	else
		for (int i = 0, j = _impStartIndex; i < end; i++, j++)
			_fftbuf[i] = _imptab[j];
	for (int i = end; i < _fftlen; i++)
		_fftbuf[i] = 0.0f;

	_fft->r2c();	// take FFT

	// normalize spectrum
	double max = 0.0;
	for (int i = 0; i < _halfFFTlen; i++) {
		int index = i << 1;
		float a = _fftbuf[index];
		float b = _fftbuf[index + 1];
		double c2 = (a * a) + (b * b);
		if (c2 > max)
			max = c2;
	}
	if (max != 0.0)
		max = _impgain / sqrt(max);
	else
		return die("CONVOLVE1", "Impulse response is all zeros.");

	_imp = new float [_fftlen];
	if (_imp == NULL)
		return -1;
	for (int i = 0; i < _fftlen; i++)
		_imp[i] = _fftbuf[i] * max;

//	for (int i = 0; i < _fftlen; i++) printf("[%d] = %f\n", i, _imp[i]);

	return 0;
}

int CONVOLVE1::configure()
{
	_inbuf = new float [RTBUFSAMPS * inputChannels()];
	_ovadd = new float [_impframes];
	if (_inbuf == NULL || _ovadd == NULL)
		return -1;
	for (int i = 0; i < _impframes; i++)
		_ovadd[i] = 0.0f;

	// read index chases write index by _impframes
	_outframes = imax(_halfFFTlen, RTBUFSAMPS) * 2;
	_outReadIndex = _outframes - _impframes;
	_outWriteIndex = 0;
	_dry = new float [_outframes];
	_wet = new float [_outframes];
	if (_dry == NULL || _wet == NULL)
		return -1;
	for (int i = 0; i < _outframes; i++)
		_dry[i] = _wet[i] = 0.0f;
	DPRINT1("_outframes: %d\n", _outframes);

	_bucket = new Obucket(_impframes, processWrapper, (void *) this);
	if (_bucket == NULL)
		return -1;

	_fft = new Offt(_fftlen);
	if (_fft == NULL)
		return -1;
	_fftbuf = _fft->getbuf();

	if (prepareImpulse() != 0)
		return -1;

	return 0;
}

void CONVOLVE1::convolve()
{
	_fft->r2c();

	_fftbuf[0] = _fftbuf[0] * _imp[0];			// DC
	_fftbuf[1] = _fftbuf[1] * _imp[1];			// Nyquist

	int i = 2;
	int j = 3;
	for ( ; i < _fftlen; i += 2, j += 2) {
		float a = (_fftbuf[i] * _imp[i]) - (_fftbuf[j] * _imp[j]);
		float b = (_fftbuf[i] * _imp[j]) + (_fftbuf[j] * _imp[i]);
		_fftbuf[i] = a;
		_fftbuf[j] = b;
	}

	_fft->c2r();
}

// Called by Obucket whenever the bucket is full (i.e., has _halfFFTlen samps).
// This static member wrapper function lets us call a non-static member
// function, which we can't pass directly as a callback to Obucket.
// See http://www.newty.de/fpt/callback.html for one explanation of this.

void CONVOLVE1::processWrapper(const float buf[], const int len, void *obj)
{
	CONVOLVE1 *myself = (CONVOLVE1 *) obj;
	myself->process(buf, len);
}

void CONVOLVE1::process(const float *buf, const int len)
{
	DPRINT1("CONVOLVE1::process (len=%d)\n", len);

	// NOTE: <len> will always be equal to _impframes
	if (_winosc)
		for (int i = 0; i < len; i++)
			_fftbuf[i] = buf[i] * _winosc->next(i);
	else
		for (int i = 0; i < len; i++)
			_fftbuf[i] = buf[i];
	for (int i = len; i < _fftlen; i++)
		_fftbuf[i] = 0.0f;

	convolve();

	for (int i = 0, j = len; i < len; i++, j++) {
		_ovadd[i] += _fftbuf[i];
		_wet[_outWriteIndex] = _ovadd[i];
		_dry[_outWriteIndex] = buf[i];
		incrementOutWriteIndex();
		_ovadd[i] = _fftbuf[j];
	}

//	for (int i = 0; i < _fftlen; i++) printf("[%d] = %f\n", i, _fftbuf[i]);
}

void CONVOLVE1::doupdate()
{
	double p[12];
	update(p, 12, 1 << 3 | 1 << 9 | 1 << 11);

	_amp = p[3];
	_wetpct = clamp(0.0f, p[9], 1.0f);
	_pan = p[11];
}

int CONVOLVE1::run()
{
	const int inchans = inputChannels();
	const int outchans = outputChannels();
	const int nframes = framesToRun();

	if (currentFrame() < _inframes) {
		const int insamps = nframes * inchans;
		rtgetin(_inbuf, this, insamps);
		for (int i = _inchan; i < insamps; i += inchans)
			_bucket->drop(_inbuf[i]);
	}
	else {
		for (int i = 0; i < nframes; i++)
			_bucket->drop(0.0f);
	}
	// If in last run invocation, make sure everything in bucket is processed.
	if (currentFrame() + nframes >= nSamps())
		_bucket->flush();

	float drypct = 1.0 - _wetpct;

	for (int i = 0; i < nframes; i++) {
		if (--_branch <= 0) {
			doupdate();
			drypct = 1.0 - _wetpct;
			_branch = getSkip();
		}

		float out[2];
		out[0] = (_wet[_outReadIndex] * _wetpct) + (_dry[_outReadIndex] * drypct);
		incrementOutReadIndex();
		out[0] *= _amp;

		if (outchans == 2) {
			out[1] = out[0] * (1.0 - _pan);
			out[0] *= _pan;
		}

		rtaddout(out);
		increment();
	}

	return framesToRun();
}

Instrument *makeCONVOLVE1()
{
	CONVOLVE1 *inst;

	inst = new CONVOLVE1();
	inst->set_bus_config("CONVOLVE1");

	return inst;
}

void rtprofile()
{
	RT_INTRO("CONVOLVE1", makeCONVOLVE1);
}

<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "browser/media/media_stream_devices_controller.h"

#include "browser/media/media_capture_devices_dispatcher.h"

#include "content/public/browser/desktop_media_id.h"
#include "content/public/common/media_stream_request.h"

namespace brightray {

namespace {

bool HasAnyAvailableDevice() {
  const content::MediaStreamDevices& audio_devices =
      MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices();
  const content::MediaStreamDevices& video_devices =
      MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();

  return !audio_devices.empty() || !video_devices.empty();
}

}  // namespace

MediaStreamDevicesController::MediaStreamDevicesController(
    const content::MediaStreamRequest& request,
    const content::MediaResponseCallback& callback)
    : request_(request),
      callback_(callback),
      // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
      // and microphone to avoid popping two infobars.
      microphone_requested_(
          request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
          request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY),
      webcam_requested_(
          request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
          request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) {
}

MediaStreamDevicesController::~MediaStreamDevicesController() {
  if (!callback_.is_null()) {
    callback_.Run(content::MediaStreamDevices(),
                  content::MEDIA_DEVICE_INVALID_STATE,
                  std::unique_ptr<content::MediaStreamUI>());
  }
}

bool MediaStreamDevicesController::TakeAction() {
  // Do special handling of desktop screen cast.
  if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
      request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE ||
      request_.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE ||
      request_.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
    HandleUserMediaRequest();
    return true;
  }

  // Deny the request if there is no device attached to the OS.
  if (!HasAnyAvailableDevice()) {
    Deny(content::MEDIA_DEVICE_NO_HARDWARE);
    return true;
  }

  Accept();
  return true;
}

void MediaStreamDevicesController::Accept() {
  // Get the default devices for the request.
  content::MediaStreamDevices devices;
  if (microphone_requested_ || webcam_requested_) {
    switch (request_.request_type) {
      case content::MEDIA_OPEN_DEVICE_PEPPER_ONLY: {
        const content::MediaStreamDevice* device = nullptr;
        // For open device request pick the desired device or fall back to the
        // first available of the given type.
        if (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
          device = MediaCaptureDevicesDispatcher::GetInstance()->
              GetRequestedAudioDevice(request_.requested_audio_device_id);
          // TODO(wjia): Confirm this is the intended behavior.
          if (!device) {
            device = MediaCaptureDevicesDispatcher::GetInstance()->
                GetFirstAvailableAudioDevice();
          }
        } else if (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
          // Pepper API opens only one device at a time.
          device = MediaCaptureDevicesDispatcher::GetInstance()->
              GetRequestedVideoDevice(request_.requested_video_device_id);
          // TODO(wjia): Confirm this is the intended behavior.
          if (!device) {
            device = MediaCaptureDevicesDispatcher::GetInstance()->
                GetFirstAvailableVideoDevice();
          }
        }
        if (device)
          devices.push_back(*device);
        break;
      } case content::MEDIA_GENERATE_STREAM: {
        bool needs_audio_device = microphone_requested_;
        bool needs_video_device = webcam_requested_;

        // Get the exact audio or video device if an id is specified.
        if (!request_.requested_audio_device_id.empty()) {
          const content::MediaStreamDevice* audio_device =
              MediaCaptureDevicesDispatcher::GetInstance()->
                  GetRequestedAudioDevice(request_.requested_audio_device_id);
          if (audio_device) {
            devices.push_back(*audio_device);
            needs_audio_device = false;
          }
        }
        if (!request_.requested_video_device_id.empty()) {
          const content::MediaStreamDevice* video_device =
              MediaCaptureDevicesDispatcher::GetInstance()->
                  GetRequestedVideoDevice(request_.requested_video_device_id);
          if (video_device) {
            devices.push_back(*video_device);
            needs_video_device = false;
          }
        }

        // If either or both audio and video devices were requested but not
        // specified by id, get the default devices.
        if (needs_audio_device || needs_video_device) {
          MediaCaptureDevicesDispatcher::GetInstance()->
              GetDefaultDevices(needs_audio_device,
                                needs_video_device,
                                &devices);
        }
        break;
      } case content::MEDIA_DEVICE_ACCESS:
        // Get the default devices for the request.
        MediaCaptureDevicesDispatcher::GetInstance()->
            GetDefaultDevices(microphone_requested_,
                              webcam_requested_,
                              &devices);
        break;
      case content::MEDIA_ENUMERATE_DEVICES:
        // Do nothing.
        NOTREACHED();
        break;
    }
  }

  content::MediaResponseCallback cb = callback_;
  callback_.Reset();
  cb.Run(devices, content::MEDIA_DEVICE_OK, std::unique_ptr<content::MediaStreamUI>());
}

void MediaStreamDevicesController::Deny(content::MediaStreamRequestResult result) {
  content::MediaResponseCallback cb = callback_;
  callback_.Reset();
  cb.Run(content::MediaStreamDevices(),
         result,
         std::unique_ptr<content::MediaStreamUI>());
}

void MediaStreamDevicesController::HandleUserMediaRequest() {
  content::MediaStreamDevices devices;

  if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) {
    devices.push_back(content::MediaStreamDevice(
        content::MEDIA_TAB_AUDIO_CAPTURE, "", ""));
  }
  if (request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
    devices.push_back(content::MediaStreamDevice(
        content::MEDIA_TAB_VIDEO_CAPTURE, "", ""));
  }
  if (request_.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) {
    devices.push_back(content::MediaStreamDevice(
        content::MEDIA_DESKTOP_AUDIO_CAPTURE, "loopback", "System Audio"));
  }
  if (request_.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
    content::DesktopMediaID screen_id;
    // If the device id wasn't specified then this is a screen capture request
    // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
    if (request_.requested_video_device_id.empty()) {
      screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
                                          -1  /* kFullDesktopScreenId */);
    } else {
      screen_id =
          content::DesktopMediaID::Parse(request_.requested_video_device_id);
    }

    devices.push_back(
        content::MediaStreamDevice(content::MEDIA_DESKTOP_VIDEO_CAPTURE,
                                   screen_id.ToString(), "Screen"));
  }

  content::MediaResponseCallback cb = callback_;
  callback_.Reset();
  cb.Run(devices,
         devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE :
                           content::MEDIA_DEVICE_OK,
         std::unique_ptr<content::MediaStreamUI>());
}

}  // namespace brightray
<commit_msg>There is no content::MEDIA_ENUMERATE_DEVICES anymore<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "browser/media/media_stream_devices_controller.h"

#include "browser/media/media_capture_devices_dispatcher.h"

#include "content/public/browser/desktop_media_id.h"
#include "content/public/common/media_stream_request.h"

namespace brightray {

namespace {

bool HasAnyAvailableDevice() {
  const content::MediaStreamDevices& audio_devices =
      MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices();
  const content::MediaStreamDevices& video_devices =
      MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();

  return !audio_devices.empty() || !video_devices.empty();
}

}  // namespace

MediaStreamDevicesController::MediaStreamDevicesController(
    const content::MediaStreamRequest& request,
    const content::MediaResponseCallback& callback)
    : request_(request),
      callback_(callback),
      // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
      // and microphone to avoid popping two infobars.
      microphone_requested_(
          request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
          request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY),
      webcam_requested_(
          request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
          request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) {
}

MediaStreamDevicesController::~MediaStreamDevicesController() {
  if (!callback_.is_null()) {
    callback_.Run(content::MediaStreamDevices(),
                  content::MEDIA_DEVICE_INVALID_STATE,
                  std::unique_ptr<content::MediaStreamUI>());
  }
}

bool MediaStreamDevicesController::TakeAction() {
  // Do special handling of desktop screen cast.
  if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
      request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE ||
      request_.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE ||
      request_.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
    HandleUserMediaRequest();
    return true;
  }

  // Deny the request if there is no device attached to the OS.
  if (!HasAnyAvailableDevice()) {
    Deny(content::MEDIA_DEVICE_NO_HARDWARE);
    return true;
  }

  Accept();
  return true;
}

void MediaStreamDevicesController::Accept() {
  // Get the default devices for the request.
  content::MediaStreamDevices devices;
  if (microphone_requested_ || webcam_requested_) {
    switch (request_.request_type) {
      case content::MEDIA_OPEN_DEVICE_PEPPER_ONLY: {
        const content::MediaStreamDevice* device = nullptr;
        // For open device request pick the desired device or fall back to the
        // first available of the given type.
        if (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
          device = MediaCaptureDevicesDispatcher::GetInstance()->
              GetRequestedAudioDevice(request_.requested_audio_device_id);
          // TODO(wjia): Confirm this is the intended behavior.
          if (!device) {
            device = MediaCaptureDevicesDispatcher::GetInstance()->
                GetFirstAvailableAudioDevice();
          }
        } else if (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
          // Pepper API opens only one device at a time.
          device = MediaCaptureDevicesDispatcher::GetInstance()->
              GetRequestedVideoDevice(request_.requested_video_device_id);
          // TODO(wjia): Confirm this is the intended behavior.
          if (!device) {
            device = MediaCaptureDevicesDispatcher::GetInstance()->
                GetFirstAvailableVideoDevice();
          }
        }
        if (device)
          devices.push_back(*device);
        break;
      } case content::MEDIA_GENERATE_STREAM: {
        bool needs_audio_device = microphone_requested_;
        bool needs_video_device = webcam_requested_;

        // Get the exact audio or video device if an id is specified.
        if (!request_.requested_audio_device_id.empty()) {
          const content::MediaStreamDevice* audio_device =
              MediaCaptureDevicesDispatcher::GetInstance()->
                  GetRequestedAudioDevice(request_.requested_audio_device_id);
          if (audio_device) {
            devices.push_back(*audio_device);
            needs_audio_device = false;
          }
        }
        if (!request_.requested_video_device_id.empty()) {
          const content::MediaStreamDevice* video_device =
              MediaCaptureDevicesDispatcher::GetInstance()->
                  GetRequestedVideoDevice(request_.requested_video_device_id);
          if (video_device) {
            devices.push_back(*video_device);
            needs_video_device = false;
          }
        }

        // If either or both audio and video devices were requested but not
        // specified by id, get the default devices.
        if (needs_audio_device || needs_video_device) {
          MediaCaptureDevicesDispatcher::GetInstance()->
              GetDefaultDevices(needs_audio_device,
                                needs_video_device,
                                &devices);
        }
        break;
      } case content::MEDIA_DEVICE_ACCESS:
        // Get the default devices for the request.
        MediaCaptureDevicesDispatcher::GetInstance()->
            GetDefaultDevices(microphone_requested_,
                              webcam_requested_,
                              &devices);
        break;
    }
  }

  content::MediaResponseCallback cb = callback_;
  callback_.Reset();
  cb.Run(devices, content::MEDIA_DEVICE_OK, std::unique_ptr<content::MediaStreamUI>());
}

void MediaStreamDevicesController::Deny(content::MediaStreamRequestResult result) {
  content::MediaResponseCallback cb = callback_;
  callback_.Reset();
  cb.Run(content::MediaStreamDevices(),
         result,
         std::unique_ptr<content::MediaStreamUI>());
}

void MediaStreamDevicesController::HandleUserMediaRequest() {
  content::MediaStreamDevices devices;

  if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) {
    devices.push_back(content::MediaStreamDevice(
        content::MEDIA_TAB_AUDIO_CAPTURE, "", ""));
  }
  if (request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
    devices.push_back(content::MediaStreamDevice(
        content::MEDIA_TAB_VIDEO_CAPTURE, "", ""));
  }
  if (request_.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) {
    devices.push_back(content::MediaStreamDevice(
        content::MEDIA_DESKTOP_AUDIO_CAPTURE, "loopback", "System Audio"));
  }
  if (request_.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
    content::DesktopMediaID screen_id;
    // If the device id wasn't specified then this is a screen capture request
    // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
    if (request_.requested_video_device_id.empty()) {
      screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
                                          -1  /* kFullDesktopScreenId */);
    } else {
      screen_id =
          content::DesktopMediaID::Parse(request_.requested_video_device_id);
    }

    devices.push_back(
        content::MediaStreamDevice(content::MEDIA_DESKTOP_VIDEO_CAPTURE,
                                   screen_id.ToString(), "Screen"));
  }

  content::MediaResponseCallback cb = callback_;
  callback_.Reset();
  cb.Run(devices,
         devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE :
                           content::MEDIA_DEVICE_OK,
         std::unique_ptr<content::MediaStreamUI>());
}

}  // namespace brightray
<|endoftext|>


<commit_before>///
/// @file  IteratorHelper.cpp
///        Functions used to calculate the next start and stop
///        numbers for primesieve::iterator.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/IteratorHelper.hpp>
#include <primesieve/PrimeGenerator.hpp>
#include <primesieve/pmath.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <limits>

using namespace std;
using namespace primesieve;

namespace {

uint64_t getNextDist(uint64_t n, uint64_t dist)
{
  double x = (double) n;
  x = max(x, 16.0);
  x = sqrt(x) / log(log(x));

  uint64_t minDist = (uint64_t) x;
  uint64_t maxDist = numeric_limits<uint64_t>::max() / 4;
  uint64_t maxCachedPrime = PrimeGenerator::maxCachedPrime();

  dist = max(dist, minDist);
  dist = max(dist, maxCachedPrime);
  dist *= 4;
  dist = min(dist, maxDist);

  return dist;
}

uint64_t getPrevDist(uint64_t n, uint64_t dist)
{
  double x = (double) n;
  x = max(x, 10.0);
  double logx = ceil(log(x));

  uint64_t minDist = config::MIN_CACHE_ITERATOR;
  uint64_t maxDist = config::MAX_CACHE_ITERATOR;
  minDist /= sizeof(uint64_t);
  maxDist /= sizeof(uint64_t);
  minDist *= (uint64_t) logx;
  maxDist *= (uint64_t) logx;

  uint64_t maxCachedPrime = PrimeGenerator::maxCachedPrime();
  dist = max(dist, maxCachedPrime);
  dist *= 4;

  uint64_t defaultDist = (uint64_t) (sqrt(x) * 2);
  dist = min(dist, minDist);
  dist = max(dist, defaultDist);
  dist = min(dist, maxDist);

  return dist;
}

bool useStopHint(uint64_t start,
                 uint64_t stopHint)
{
  return stopHint >= start &&
         stopHint < numeric_limits<uint64_t>::max();
}

bool useStopHint(uint64_t start,
                 uint64_t stop,
                 uint64_t stopHint)
{
  return stopHint >= start &&
         stopHint <= stop;
}

} // namespace

namespace primesieve {

void IteratorHelper::next(uint64_t* start,
                          uint64_t* stop,
                          uint64_t stopHint,
                          uint64_t* dist)
{
  *start = checkedAdd(*stop, 1);
  uint64_t maxCachedPrime = PrimeGenerator::maxCachedPrime();

  if (*start < maxCachedPrime)
  {
    // When the stop number <= maxCachedPrime
    // primesieve::iterator uses the primes
    // cache instead of sieving and does not
    // even initialize Erat::init()
    *stop = maxCachedPrime;
    *dist = *stop - *start;
  }
  else
  {
    *dist = getNextDist(*start, *dist);
    *stop = checkedAdd(*start, *dist);

    if (useStopHint(*start, stopHint))
      *stop = checkedAdd(stopHint, maxPrimeGap(stopHint));
  }
}

void IteratorHelper::prev(uint64_t* start,
                          uint64_t* stop,
                          uint64_t stopHint,
                          uint64_t* dist)
{
  *stop = checkedSub(*start, 1);
  *dist = getPrevDist(*stop, *dist);
  *start = checkedSub(*stop, *dist);

  if (useStopHint(*start, *stop, stopHint))
    *start = checkedSub(stopHint, maxPrimeGap(stopHint));
}

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  IteratorHelper.cpp
///        Functions used to calculate the next start and stop
///        numbers for primesieve::iterator.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/IteratorHelper.hpp>
#include <primesieve/PrimeGenerator.hpp>
#include <primesieve/pmath.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <limits>

using namespace std;
using namespace primesieve;

namespace {

uint64_t getNextDist(uint64_t n, uint64_t dist)
{
  double x = (double) n;
  uint64_t tinyDist = PrimeGenerator::maxCachedPrime() * 4;
  uint64_t minDist = (uint64_t) sqrt(x);
  uint64_t maxDist = 1ull << 60;

  dist *= 4;
  dist = max(dist, tinyDist);
  dist = max(dist, minDist);
  dist = min(dist, maxDist);

  return dist;
}

uint64_t getPrevDist(uint64_t n, uint64_t dist)
{
  double x = (double) n;
  x = max(x, 10.0);
  double logx = ceil(log(x));

  uint64_t minDist = config::MIN_CACHE_ITERATOR;
  uint64_t maxDist = config::MAX_CACHE_ITERATOR;
  minDist /= sizeof(uint64_t);
  maxDist /= sizeof(uint64_t);
  minDist *= (uint64_t) logx;
  maxDist *= (uint64_t) logx;

  uint64_t tinyDist = PrimeGenerator::maxCachedPrime() * 4;
  uint64_t defaultDist = (uint64_t) (sqrt(x) * 2);

  dist *= 4;
  dist = max(dist, tinyDist);
  dist = min(dist, minDist);
  dist = max(dist, defaultDist);
  dist = min(dist, maxDist);

  return dist;
}

bool useStopHint(uint64_t start,
                 uint64_t stopHint)
{
  return stopHint >= start &&
         stopHint < numeric_limits<uint64_t>::max();
}

bool useStopHint(uint64_t start,
                 uint64_t stop,
                 uint64_t stopHint)
{
  return stopHint >= start &&
         stopHint <= stop;
}

} // namespace

namespace primesieve {

void IteratorHelper::next(uint64_t* start,
                          uint64_t* stop,
                          uint64_t stopHint,
                          uint64_t* dist)
{
  *start = checkedAdd(*stop, 1);
  uint64_t maxCachedPrime = PrimeGenerator::maxCachedPrime();

  if (*start < maxCachedPrime)
  {
    // When the stop number <= maxCachedPrime
    // primesieve::iterator uses the primes
    // cache instead of sieving and does not
    // even initialize Erat::init()
    *stop = maxCachedPrime;
    *dist = *stop - *start;
  }
  else
  {
    *dist = getNextDist(*start, *dist);
    *stop = checkedAdd(*start, *dist);

    if (useStopHint(*start, stopHint))
      *stop = checkedAdd(stopHint, maxPrimeGap(stopHint));
  }
}

void IteratorHelper::prev(uint64_t* start,
                          uint64_t* stop,
                          uint64_t stopHint,
                          uint64_t* dist)
{
  *stop = checkedSub(*start, 1);
  *dist = getPrevDist(*stop, *dist);
  *start = checkedSub(*stop, *dist);

  if (useStopHint(*start, *stop, stopHint))
    *start = checkedSub(stopHint, maxPrimeGap(stopHint));
}

} // namespace
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "MemoryFunction.h"

#ifdef WIN32

#include <windows.h>

#elif defined(__APPLE__)

#include "TargetConditionals.h"
#include <mach/mach_init.h>
#include <mach/vm_map.h>
extern "C" void __clear_cache(void* begin, void* end);

#endif

CMemoryFunction::CMemoryFunction()
: m_code(nullptr)
, m_size(0)
{

}

CMemoryFunction::CMemoryFunction(const void* code, size_t size)
: m_code(nullptr)
{
#ifdef WIN32
	m_size = size;
	m_code = malloc(size);
	memcpy(m_code, code, size);

	DWORD oldProtect = 0;
	BOOL result = VirtualProtect(m_code, size, PAGE_EXECUTE_READWRITE, &oldProtect);
	assert(result == TRUE);
#elif defined(__APPLE__)
	vm_size_t page_size = 0;
	host_page_size(mach_task_self(), &page_size);
	unsigned int allocSize = ((size + page_size - 1) / page_size) * page_size;
	vm_allocate(mach_task_self(), reinterpret_cast<vm_address_t*>(&m_code), allocSize, TRUE);
	memcpy(m_code, code, size);
	__clear_cache(m_code, reinterpret_cast<uint8*>(m_code) + size);
	kern_return_t result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(m_code), size, 0, VM_PROT_READ | VM_PROT_EXECUTE);
	assert(result == 0);
	m_size = allocSize;
#endif
}

CMemoryFunction::~CMemoryFunction()
{
	Reset();
}

void CMemoryFunction::Reset()
{
	if(m_code != nullptr)
	{
#ifdef WIN32
		free(m_code);
#elif defined(__APPLE__)
		vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(m_code), m_size);
#endif
	}
	m_code = nullptr;
	m_size = 0;
}

bool CMemoryFunction::IsEmpty() const
{
	return m_code == nullptr;
}

CMemoryFunction& CMemoryFunction::operator =(CMemoryFunction&& rhs)
{
	Reset();
	std::swap(m_code, rhs.m_code);
	std::swap(m_size, rhs.m_size);
	return (*this);
}

void CMemoryFunction::operator()(void* context)
{
	typedef void (*FctType)(void*);
	auto fct = reinterpret_cast<FctType>(m_code);
	fct(context);
}

void* CMemoryFunction::GetCode() const
{
	return m_code;
}

size_t CMemoryFunction::GetSize() const
{
	return m_size;
}
<commit_msg>Compilation fix for iOS.<commit_after>#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "MemoryFunction.h"

#ifdef WIN32

#include <windows.h>

#elif defined(__APPLE__)

#include "TargetConditionals.h"
#include <mach/mach_init.h>
#include <mach/vm_map.h>

#if TARGET_IPHONE_SIMULATOR
extern "C" void __clear_cache(void* begin, void* end);
#endif

#endif

CMemoryFunction::CMemoryFunction()
: m_code(nullptr)
, m_size(0)
{

}

CMemoryFunction::CMemoryFunction(const void* code, size_t size)
: m_code(nullptr)
{
#ifdef WIN32
	m_size = size;
	m_code = malloc(size);
	memcpy(m_code, code, size);

	DWORD oldProtect = 0;
	BOOL result = VirtualProtect(m_code, size, PAGE_EXECUTE_READWRITE, &oldProtect);
	assert(result == TRUE);
#elif defined(__APPLE__)
	vm_size_t page_size = 0;
	host_page_size(mach_task_self(), &page_size);
	unsigned int allocSize = ((size + page_size - 1) / page_size) * page_size;
	vm_allocate(mach_task_self(), reinterpret_cast<vm_address_t*>(&m_code), allocSize, TRUE);
	memcpy(m_code, code, size);
	__clear_cache(m_code, reinterpret_cast<uint8*>(m_code) + size);
	kern_return_t result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(m_code), size, 0, VM_PROT_READ | VM_PROT_EXECUTE);
	assert(result == 0);
	m_size = allocSize;
#endif
}

CMemoryFunction::~CMemoryFunction()
{
	Reset();
}

void CMemoryFunction::Reset()
{
	if(m_code != nullptr)
	{
#ifdef WIN32
		free(m_code);
#elif defined(__APPLE__)
		vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(m_code), m_size);
#endif
	}
	m_code = nullptr;
	m_size = 0;
}

bool CMemoryFunction::IsEmpty() const
{
	return m_code == nullptr;
}

CMemoryFunction& CMemoryFunction::operator =(CMemoryFunction&& rhs)
{
	Reset();
	std::swap(m_code, rhs.m_code);
	std::swap(m_size, rhs.m_size);
	return (*this);
}

void CMemoryFunction::operator()(void* context)
{
	typedef void (*FctType)(void*);
	auto fct = reinterpret_cast<FctType>(m_code);
	fct(context);
}

void* CMemoryFunction::GetCode() const
{
	return m_code;
}

size_t CMemoryFunction::GetSize() const
{
	return m_size;
}
<|endoftext|>


<commit_before>#include "TTextEditor.h"
#include "TText.h"
#include "TGTextEntry.h"
#include "TGNumberEntry.h"
#include "TGLabel.h"

ClassImp(TTextEditor)

enum ELatexID{
   kText_Text = 0, kText_Xpos, kText_Ypos, kText_Angle, kText_Size
};

//______________________________________________________________________________
TTextEditor::TTextEditor(const TGWindow *p,
                  Int_t width, Int_t height,
                  UInt_t options, Pixel_t back)
                  : TGedFrame(p, width, height, options | kVerticalFrame, back)
{
   // TTextEditor constructor.

   fText = 0;

   // start initializing the window components
   MakeTitle("Text String");

   fText = new TGTextEntry(this, new TGTextBuffer(50), kText_Text);
   fText->Resize(135, fText->GetDefaultHeight());
   fText->SetToolTipText("Enter the text string");
   AddFrame(fText, new TGLayoutHints(kLHintsLeft, 3, 1, 2, 5));

   TGCompositeFrame *f1 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl1 = new TGLabel(f1,"X Position");
   fXpos = new TGNumberEntry(f1, 4, 2, kText_Xpos, TGNumberEntry::kNESRealTwo,
   TGNumberEntry::kNEANonNegative);
   fXpos->Resize(50, 20);
   f1->AddFrame(lbl1, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f1->AddFrame(fXpos, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f1, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));

   TGCompositeFrame *f2 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl2 = new TGLabel(f2,"Y Position");
   fYpos = new TGNumberEntry(f2, 4, 2, kText_Ypos, TGNumberEntry::kNESRealTwo,
   TGNumberEntry::kNEANonNegative);
   fYpos->Resize(50, 20);
   f2->AddFrame(lbl2, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f2->AddFrame(fYpos, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f2, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));

   TGCompositeFrame *f3 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl3 = new TGLabel(f3,"Text Angle");
   fAngle = new TGNumberEntry(f3, 4, 2, kText_Angle, TGNumberEntry::kNESInteger,
   TGNumberEntry::kNEANonNegative);
   fAngle->Resize(50, 20);
   f3->AddFrame(lbl3, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f3->AddFrame(fAngle, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f3, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));

   TGCompositeFrame *f4 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl4 = new TGLabel(f4,"Text Size");
   fSize = new TGNumberEntry(f4, 4, 2, kText_Size, TGNumberEntry::kNESRealTwo,
   TGNumberEntry::kNEANonNegative);
   fSize->Resize(50, 20);
   f4->AddFrame(lbl4, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f4->AddFrame(fSize, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f4, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));
}

//______________________________________________________________________________
TTextEditor::~TTextEditor()
{
   // TTextEditor destructor.
}

//______________________________________________________________________________
void TTextEditor::SetModel(TObject *obj)
{
   // Set model.

   fEditedText = (TText*) (obj);

   fAvoidSignal = kTRUE;
   fText->SetText(fEditedText->GetTitle());
   fXpos->SetNumber(fEditedText->GetX());
   fYpos->SetNumber(fEditedText->GetY());
   fAngle->SetNumber(fEditedText->GetTextAngle());
   fSize->SetNumber(fEditedText->GetTextSize());

   if (fInit) ConnectSignals2Slots();
   fAvoidSignal = kFALSE;
}

//_____________________________________________________________________________
void TTextEditor::ConnectSignals2Slots()
{
   // Connect signals to slots.

   fText->Connect("TextChanged(const char *)","TTextEditor",this,"DoText(const char *)");
   fXpos->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoXpos()");
   fYpos->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoYpos()");
   fAngle->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoAngle()");
   fSize->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoSize()");

   fInit = kFALSE;  // connect the slots to the signals only once
}

//______________________________________________________________________________
void TTextEditor::DoAngle()
{
   // Slot for setting the text Angle.

   if (fAvoidSignal) return;
   fEditedText->SetTextAngle(fAngle->GetNumber());
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoSize()
{
   // Slot for setting the text Size.

   if (fAvoidSignal) return;
   fEditedText->SetTextSize(fSize->GetNumber());
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoText(const char *text)
{
   // Slot for setting the text string.

   if (fAvoidSignal) return;
   fEditedText->SetTitle(text);
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoXpos()
{
   // Slot for setting the text X position.

   if (fAvoidSignal) return;
   fEditedText->SetX(fXpos->GetNumber());
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoYpos()
{
   // Slot for setting the text Y position.

   if (fAvoidSignal) return;
   fEditedText->SetY(fYpos->GetNumber());
   Update();
}<commit_msg>Fix Jira issue #ROOT-6221: Text editor does not allow negative positions<commit_after>#include "TTextEditor.h"
#include "TText.h"
#include "TGTextEntry.h"
#include "TGNumberEntry.h"
#include "TGLabel.h"

ClassImp(TTextEditor)

enum ELatexID{
   kText_Text = 0, kText_Xpos, kText_Ypos, kText_Angle, kText_Size
};

//______________________________________________________________________________
TTextEditor::TTextEditor(const TGWindow *p,
                  Int_t width, Int_t height,
                  UInt_t options, Pixel_t back)
                  : TGedFrame(p, width, height, options | kVerticalFrame, back)
{
   // TTextEditor constructor.

   fText = 0;

   // start initializing the window components
   MakeTitle("Text String");

   fText = new TGTextEntry(this, new TGTextBuffer(50), kText_Text);
   fText->Resize(135, fText->GetDefaultHeight());
   fText->SetToolTipText("Enter the text string");
   AddFrame(fText, new TGLayoutHints(kLHintsLeft, 3, 1, 2, 5));

   TGCompositeFrame *f1 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl1 = new TGLabel(f1,"X Position");
   fXpos = new TGNumberEntry(f1, 4, 2, kText_Xpos, TGNumberEntry::kNESRealTwo,
   TGNumberEntry::kNEAAnyNumber);
   fXpos->Resize(50, 20);
   f1->AddFrame(lbl1, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f1->AddFrame(fXpos, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f1, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));

   TGCompositeFrame *f2 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl2 = new TGLabel(f2,"Y Position");
   fYpos = new TGNumberEntry(f2, 4, 2, kText_Ypos, TGNumberEntry::kNESRealTwo,
   TGNumberEntry::kNEAAnyNumber);
   fYpos->Resize(50, 20);
   f2->AddFrame(lbl2, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f2->AddFrame(fYpos, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f2, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));

   TGCompositeFrame *f3 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl3 = new TGLabel(f3,"Text Angle");
   fAngle = new TGNumberEntry(f3, 4, 2, kText_Angle, TGNumberEntry::kNESInteger,
   TGNumberEntry::kNEANonNegative);
   fAngle->Resize(50, 20);
   f3->AddFrame(lbl3, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f3->AddFrame(fAngle, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f3, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));

   TGCompositeFrame *f4 = new TGCompositeFrame(this, 120, 20, kHorizontalFrame);
   TGLabel *lbl4 = new TGLabel(f4,"Text Size");
   fSize = new TGNumberEntry(f4, 4, 2, kText_Size, TGNumberEntry::kNESRealTwo,
   TGNumberEntry::kNEANonNegative);
   fSize->Resize(50, 20);
   f4->AddFrame(lbl4, new TGLayoutHints(kLHintsLeft,1, 1, 1, 1));
   f4->AddFrame(fSize, new TGLayoutHints(kLHintsLeft, 7, 1, 1, 1));
   AddFrame(f4, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));
}

//______________________________________________________________________________
TTextEditor::~TTextEditor()
{
   // TTextEditor destructor.
}

//______________________________________________________________________________
void TTextEditor::SetModel(TObject *obj)
{
   // Set model.

   fEditedText = (TText*) (obj);

   fAvoidSignal = kTRUE;
   fText->SetText(fEditedText->GetTitle());
   fXpos->SetNumber(fEditedText->GetX());
   fYpos->SetNumber(fEditedText->GetY());
   fAngle->SetNumber(fEditedText->GetTextAngle());
   fSize->SetNumber(fEditedText->GetTextSize());

   if (fInit) ConnectSignals2Slots();
   fAvoidSignal = kFALSE;
}

//_____________________________________________________________________________
void TTextEditor::ConnectSignals2Slots()
{
   // Connect signals to slots.

   fText->Connect("TextChanged(const char *)","TTextEditor",this,"DoText(const char *)");
   fXpos->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoXpos()");
   fYpos->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoYpos()");
   fAngle->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoAngle()");
   fSize->Connect("ValueSet(Long_t)", "TTextEditor", this, "DoSize()");

   fInit = kFALSE;  // connect the slots to the signals only once
}

//______________________________________________________________________________
void TTextEditor::DoAngle()
{
   // Slot for setting the text Angle.

   if (fAvoidSignal) return;
   fEditedText->SetTextAngle(fAngle->GetNumber());
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoSize()
{
   // Slot for setting the text Size.

   if (fAvoidSignal) return;
   fEditedText->SetTextSize(fSize->GetNumber());
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoText(const char *text)
{
   // Slot for setting the text string.

   if (fAvoidSignal) return;
   fEditedText->SetTitle(text);
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoXpos()
{
   // Slot for setting the text X position.

   if (fAvoidSignal) return;
   fEditedText->SetX(fXpos->GetNumber());
   Update();
}

//______________________________________________________________________________
void TTextEditor::DoYpos()
{
   // Slot for setting the text Y position.

   if (fAvoidSignal) return;
   fEditedText->SetY(fYpos->GetNumber());
   Update();
}<|endoftext|>


<commit_before>// @(#)root/gui:$Name:  $:$Id: TRootHelpDialog.cxx,v 1.2 2000/07/03 18:55:32 rdm Exp $
// Author: Fons Rademakers   24/02/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootHelpDialog                                                      //
//                                                                      //
// A TRootHelpDialog is used to display help text (or any text in a     //
// dialog window). There is on OK button to popdown the dialog.         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRootHelpDialog.h"
#include "TGButton.h"
//#include "TGTextView.h"
#include "TGTextEdit.h"

ClassImp(TRootHelpDialog)

//______________________________________________________________________________
TRootHelpDialog::TRootHelpDialog(const TGWindow *main,
    const char *title, UInt_t w, UInt_t h) :
    TGTransientFrame(gClient->GetRoot(), main, w, h)
{
   // Create a help text dialog.

//   fView = new TGTextView(this, w, h, kSunkenFrame | kDoubleBorder);
   fView = new TGTextEdit(this, w, h, kSunkenFrame | kDoubleBorder);
   fL1 = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 3, 3, 3, 3);
   AddFrame(fView, fL1);

   fOK = new TGTextButton(this, "  &OK  ");
   fL2 = new TGLayoutHints(kLHintsBottom | kLHintsCenterX, 0, 0, 5, 5);
   AddFrame(fOK, fL2);

   SetWindowName(title);
   SetIconName(title);

   MapSubwindows();

   Resize(GetDefaultSize());

   // position relative to the parent's window
   Window_t wdum;
   int ax, ay;
   gVirtualX->TranslateCoordinates(main->GetId(), GetParent()->GetId(),
                          ((TGFrame *) main)->GetWidth() - (fWidth >> 1),
                          (((TGFrame *) main)->GetHeight() - fHeight) >> 1,
                          ax, ay, wdum);
   Move(ax, ay);
   SetWMPosition(ax, ay);
}

//______________________________________________________________________________
TRootHelpDialog::~TRootHelpDialog()
{
   // Delete help text dialog.

   delete fView;
   delete fOK;
   delete fL1;
   delete fL2;
}

//______________________________________________________________________________
void TRootHelpDialog::Popup()
{
   // Show help dialog.

   MapWindow();
}

//______________________________________________________________________________
void TRootHelpDialog::SetText(const char *helpText)
{
   // Set help text from helpText buffer in TGTextView.

   //fView->LoadBuffer(helpText);
   fView->LoadFile("/user/rdm/root/test/Makefile");
}

//______________________________________________________________________________
void TRootHelpDialog::AddText(const char *helpText)
{
   // Add help text from helpText buffer to already existing text in TGTextView.

   TGText tt;
   tt.LoadBuffer(helpText);
   fView->AddText(&tt);
}

//______________________________________________________________________________
void TRootHelpDialog::CloseWindow()
{
   // Called when closed via window manager action.

   delete this;
}

//______________________________________________________________________________
Bool_t TRootHelpDialog::ProcessMessage(Long_t msg, Long_t, Long_t)
{
   // Process OK button.

   switch (GET_MSG(msg)) {
      case kC_COMMAND:
         switch (GET_SUBMSG(msg)) {
            case kCM_BUTTON:
               // Only one button and one action...
               delete this;
               break;
            default:
               break;
         }
      default:
         break;
   }

   return kTRUE;
}

<commit_msg>revert to original version<commit_after>// @(#)root/gui:$Name:  $:$Id: TRootHelpDialog.cxx,v 1.2 2000/07/03 18:55:32 rdm Exp $
// Author: Fons Rademakers   24/02/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootHelpDialog                                                      //
//                                                                      //
// A TRootHelpDialog is used to display help text (or any text in a     //
// dialog window). There is on OK button to popdown the dialog.         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRootHelpDialog.h"
#include "TGButton.h"
#include "TGTextView.h"

ClassImp(TRootHelpDialog)

//______________________________________________________________________________
TRootHelpDialog::TRootHelpDialog(const TGWindow *main,
    const char *title, UInt_t w, UInt_t h) :
    TGTransientFrame(gClient->GetRoot(), main, w, h)
{
   // Create a help text dialog.

   fView = new TGTextView(this, w, h, kSunkenFrame | kDoubleBorder);
   fL1 = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 3, 3, 3, 3);
   AddFrame(fView, fL1);

   fOK = new TGTextButton(this, "  &OK  ");
   fL2 = new TGLayoutHints(kLHintsBottom | kLHintsCenterX, 0, 0, 5, 5);
   AddFrame(fOK, fL2);

   SetWindowName(title);
   SetIconName(title);

   MapSubwindows();

   Resize(GetDefaultSize());

   // position relative to the parent's window
   Window_t wdum;
   int ax, ay;
   gVirtualX->TranslateCoordinates(main->GetId(), GetParent()->GetId(),
                          ((TGFrame *) main)->GetWidth() - (fWidth >> 1),
                          (((TGFrame *) main)->GetHeight() - fHeight) >> 1,
                          ax, ay, wdum);
   Move(ax, ay);
   SetWMPosition(ax, ay);
}

//______________________________________________________________________________
TRootHelpDialog::~TRootHelpDialog()
{
   // Delete help text dialog.

   delete fView;
   delete fOK;
   delete fL1;
   delete fL2;
}

//______________________________________________________________________________
void TRootHelpDialog::Popup()
{
   // Show help dialog.

   MapWindow();
}

//______________________________________________________________________________
void TRootHelpDialog::SetText(const char *helpText)
{
   // Set help text from helpText buffer in TGTextView.

   fView->LoadBuffer(helpText);
}

//______________________________________________________________________________
void TRootHelpDialog::AddText(const char *helpText)
{
   // Add help text from helpText buffer to already existing text in TGTextView.

   TGText tt;
   tt.LoadBuffer(helpText);
   fView->AddText(&tt);
}

//______________________________________________________________________________
void TRootHelpDialog::CloseWindow()
{
   // Called when closed via window manager action.

   delete this;
}

//______________________________________________________________________________
Bool_t TRootHelpDialog::ProcessMessage(Long_t msg, Long_t, Long_t)
{
   // Process OK button.

   switch (GET_MSG(msg)) {
      case kC_COMMAND:
         switch (GET_SUBMSG(msg)) {
            case kCM_BUTTON:
               // Only one button and one action...
               delete this;
               break;
            default:
               break;
         }
      default:
         break;
   }

   return kTRUE;
}

<|endoftext|>