<commit_before>#ifndef INCLUDE_AL_ISOSURFACE_HPP
#define INCLUDE_AL_ISOSURFACE_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	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 the University of California nor the names of its
		contributors 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 HOLDER 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.

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com

	This file incorporates work covered by the following copyright(s) and
	permission notice(s):

		Author: Raghavendra Chandrashekara
		Email: rc99@doc.ic.ac.uk, rchandrashekara@hotmail.com
		Last Modified: 5/8/2000

		This work incorporates work covered by the following copyright and
		permission notice:

			Marching Cubes Example Program
			by Cory Bloyd (corysama@yahoo.com)

			A simple, portable and complete implementation of the Marching Cubes
			and Marching Tetrahedrons algorithms in a single source file.
			There are many ways that this code could be made faster, but the
			intent is for the code to be easy to understand.

			For a description of the algorithm go to
			http://astronomy.swin.edu.au/pbourke/modelling/polygonise/

			This code is public domain.
*/

#include <ciso646> // http://marshall.calepin.co/c-and-xcode-46.html

#include "allocore/system/al_Config.h"
#ifdef AL_WINDOWS
	#include <tr1/unordered_map>
	//#include <unordered_map>
#else
	#ifdef _LIBCPP_VERSION
		#include <unordered_map>
	#else
		#include <tr1/unordered_map>
	#endif
#endif
#include <map>
#include <vector>
#include "allocore/types/al_Buffer.hpp"
#include "allocore/graphics/al_Graphics.hpp"

namespace al{

/// Isosurface generated using marching cubes
class Isosurface : public Mesh {
public:

	struct EdgeVertex {
		Vec3i pos;			// cell coordinates
		Vec3i corners[2];	// edge corners as offsets from cell coordinates
		float x, y, z;		// vertex position
		float mu;			// fraction along edge of vertex

		/// Returns position of edge vertices
		Vec3i edgePos(int i) const { return pos + corners[i]; }
	};

	struct EdgeTriangle {
		int edgeIDs[3];
	};

	struct VertexAction {
		virtual ~VertexAction(){}
		virtual void operator()(const Isosurface::EdgeVertex& v, Isosurface& s) = 0;
	};

	struct NoVertexAction : public VertexAction{
		virtual void operator()(const EdgeVertex& v, Isosurface& s){}
	};

	static NoVertexAction noVertexAction;

	/// @param[in] level	value to construct surface on
	/// @param[in] action	user defined functor called upon adding a new edge vertex
	Isosurface(float level=0, VertexAction& action = noVertexAction);

	virtual ~Isosurface();

	/// Get a field dimension
	int fieldDim(int i) const { return mNF[i]; }

	/// Get isolevel
	float level() const { return mIsolevel; }

	/// Returns true if a valid surface has been generated
	bool validSurface() const { return mValidSurface; }

	/// Gets the length, width, and height of the isosurface volume

	/// \returns true upon success and false if the surface is not valid
	///
	bool volumeLengths(double& volLengthX, double& volLengthY, double& volLengthZ) const;

	// Get unique identifier of 3d position indices
	int posID(int ix, int iy, int iz) const { return ix + mNF[0] * (iy + mNF[1] * iz); }

	template <class VEC3I>
	int posID(const VEC3I& i3) const { return posID(i3[0], i3[1], i3[2]); }

	// Get unique identifier of cell
	int cellID(int ix, int iy, int iz) const{ return 3*posID(ix,iy,iz); }

	// Get unique identifier of edge
	int edgeID(int cellID, int edgeNo) const{ return cellID + mEdgeIDOffsets[edgeNo]; }

	/// Set individual dimensions of the scalar field
	Isosurface& fieldDims(int nx, int ny, int nz);

	/// Set all dimensions of the scalar field
	Isosurface& fieldDims(int n){ return fieldDims(n,n,n); }

	/// Set individual lengths of cell
	Isosurface& cellLengths(double dx, double dy, double dz);

	/// Set all lengths of cell
	Isosurface& cellLengths(double v){ return cellLengths(v,v,v); }

	/// Set isolevel
	Isosurface& level(float v){ mIsolevel=v; return *this; }

	/// Set whether to compute normals
	Isosurface& normals(bool v){ mComputeNormals=v; return *this; }

	/// Set whether to normalize normals (if being computed)
	Isosurface& normalize(bool v){ mNormalize=v; return *this; }

	/// Begin cell-at-a-time mode
	void begin();

	/// End cell-at-a-time mode
	void end();

	/// Clear the isosurface
	void clear();

	/// Add a cell from a scalar field

	/// This should be called in between calls to begin() and end().
	///
	template <class T>
	void addCell(
		int ix, int iy, int iz,
		const T& xyz, const T& Xyz,
		const T& xYz, const T& XYz,
		const T& xyZ, const T& XyZ,
		const T& xYZ, const T& XYZ
	){
		int inds[3] = { ix, iy, iz };
		const float vals[8] = { xyz, Xyz, xYz, XYz, xyZ, XyZ, xYZ, XYZ };
		addCell(inds, vals);
	}

	/// Add a cell from a scalar field
	void addCell(const int * indices3, const float * values8);

	/// Generate isosurface from scalar field
	template <class T>
	void generate(const T * scalarField);

	/// Generate isosurface from scalar field

	/// The total number of elements in the field is expected to be nX*nY*nZ.
	/// The field elements are located at the corners of the cuboidal cells used
	/// to generate the surface. Thus, the surface is evaluated on a total of
	/// (nX-1)*(nY-1)*(nZ-1) cells.
	template <class T>
	void generate(const T * scalarField, int nX, int nY, int nZ, float cellLengthX, float cellLengthY, float cellLengthZ){
		fieldDims(nX, nY, nZ);
		cellLengths(cellLengthX, cellLengthY, cellLengthZ);
		generate(scalarField);
	}

	template <class T>
	void generate(const T * scalarField, int n, float cellLength){
		generate(scalarField, n,n,n, cellLength,cellLength,cellLength);
	}

	/// A variation that shifts & wraps all the cells by integer amounts
	template <class T>
	void generate_shifted(const T * scalarField, const int sx, const int sy, const int sz);

	void vertexAction(VertexAction& a){ mVertexAction = &a; }

	const bool inBox() const { return mInBox; }

	/// Set whether isosurface is assumed to fit snugly within a box

	/// Setting this to true will speed up extraction when the isosurface
	/// is mostly dense and box shaped, i.e., a rectangular cuboid. If the
	/// isosurface is to be computed on sparse or irregularly shaped grid, then
	/// it is recommended to set this to false to save memory.
	Isosurface& inBox(bool v);

protected:

	struct IsosurfaceHashInt{
		size_t operator()(int v) const { return v; }
	//	size_t operator()(int v) const { return v*2654435761UL; }
	};

	//#ifdef AL_WINDOWS
	//typedef std::unordered_map<int, int, IsosurfaceHashInt> EdgeToVertex;
	//#else
	#ifdef _LIBCPP_VERSION
	typedef std::unordered_map<int, int, IsosurfaceHashInt> EdgeToVertex;
	#else
	typedef std::tr1::unordered_map<int, int, IsosurfaceHashInt> EdgeToVertex;
	#endif
	//#endif
//	typedef std::tr1::unordered_map<int, VertexData, IsosurfaceHashInt> EdgeToVertex;
//	typedef std::hash_map<int, VertexData, IsosurfaceHashInt> EdgeToVertex;
//	typedef std::map<int, VertexData> EdgeToVertex;

	EdgeToVertex mEdgeToVertex;					// map from edge ID to vertex
	al::Buffer<EdgeTriangle> mEdgeTriangles;	// surface triangles in terms of edge IDs

	std::vector<int> mEdgeToVertexArray;
//	al::Buffer<int> mTempEdges;

	double mL[3];				// cell length in x, y, and z directions
	int mNF[3];					// number of field points in x, y, and z directions
	int mEdgeIDOffsets[12];		// used to obtain edge ID from vertex ID and edge number
	float mIsolevel;			// isosurface level
	VertexAction * mVertexAction;
	bool mValidSurface;			// indicates whether a valid surface is present
	bool mComputeNormals;		// whether to compute normals
	bool mNormalize;			// whether to normalize normals
	bool mInBox;

	EdgeVertex calcIntersection(int nX, int nY, int nZ, int nEdgeNo, const float * vals) const;
	void addEdgeVertex(int x, int y, int z, int cellID, int edge, const float * vals);

	void compressTriangles();
};

// Implementation ______________________________________________________________

template <class T>
void Isosurface::generate(const T * vals){
	inBox(true);
	begin();

	int Nx = mNF[0];
	int Nxy = Nx*mNF[1];

	// iterate through cubes (not field points)
	//for(int z=0; z < mNF[2]-1; ++z){
	// support transparency (assumes higher indices are farther away)
	for(int z=mNF[2]-2; z>=0; --z){
		int z0 = z   *Nxy;
		int z1 =(z+1)*Nxy;
		for(int y=0; y < mNF[1]-1; ++y){
			int y0 = y   *Nx;
			int y1 =(y+1)*Nx;

			int z0y0 = z0+y0;
			int z0y1 = z0+y1;
			int z1y0 = z1+y0;
			int z1y1 = z1+y1;

			int z0y0_1 = z0y0+1;
			int z0y1_1 = z0y1+1;
			int z1y0_1 = z1y0+1;
			int z1y1_1 = z1y1+1;

			for(int x=0; x < mNF[0]-1; ++x){

				float v8[] = {
					vals[z0y0 + x], vals[z0y0_1 + x],
					vals[z0y1 + x], vals[z0y1_1 + x],
					vals[z1y0 + x], vals[z1y0_1 + x],
					vals[z1y1 + x], vals[z1y1_1 + x]
				};

				int i3[] = {x,y,z};

				addCell(i3,	v8);
			}
		}
	}

	end();
}

// generate but shift & wrap the cubes by an integer amount:
template <class T>
void Isosurface::generate_shifted(const T * vals, const int sx, const int sy, const int sz){
	inBox(true);
	begin();

	int Nx = mNF[0];
	int Nxy = Nx*mNF[1];

	// iterate through cubes (not field points)
	//for(int z=0; z < mNF[2]-1; ++z){
	// support transparency (assumes higher indices are farther away)
	for(int z=mNF[2]-2; z>=0; --z){
		int z0 = z   *Nxy;
		int z1 =(z+1)*Nxy;
		for(int y=0; y < mNF[1]-1; ++y){
			int y0 = y   *Nx;
			int y1 =(y+1)*Nx;

			int z0y0 = z0+y0;
			int z0y1 = z0+y1;
			int z1y0 = z1+y0;
			int z1y1 = z1+y1;

			int z0y0_1 = z0y0+1;
			int z0y1_1 = z0y1+1;
			int z1y0_1 = z1y0+1;
			int z1y1_1 = z1y1+1;

			for(int x=0; x < mNF[0]-1; ++x){

				float v8[] = {
					vals[z0y0 + x], vals[z0y0_1 + x],
					vals[z0y1 + x], vals[z0y1_1 + x],
					vals[z1y0 + x], vals[z1y0_1 + x],
					vals[z1y1 + x], vals[z1y1_1 + x]
				};

				int i3[] = {x, y, z};

				addCell(i3,	v8);
			}
		}
	}

	end();
}

} // al::

#endif
<commit_msg>remove unnecessary Windows checks<commit_after>#ifndef INCLUDE_AL_ISOSURFACE_HPP
#define INCLUDE_AL_ISOSURFACE_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	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 the University of California nor the names of its
		contributors 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 HOLDER 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.

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com

	This file incorporates work covered by the following copyright(s) and
	permission notice(s):

		Author: Raghavendra Chandrashekara
		Email: rc99@doc.ic.ac.uk, rchandrashekara@hotmail.com
		Last Modified: 5/8/2000

		This work incorporates work covered by the following copyright and
		permission notice:

			Marching Cubes Example Program
			by Cory Bloyd (corysama@yahoo.com)

			A simple, portable and complete implementation of the Marching Cubes
			and Marching Tetrahedrons algorithms in a single source file.
			There are many ways that this code could be made faster, but the
			intent is for the code to be easy to understand.

			For a description of the algorithm go to
			http://astronomy.swin.edu.au/pbourke/modelling/polygonise/

			This code is public domain.
*/

#include <ciso646> // http://marshall.calepin.co/c-and-xcode-46.html

#include "allocore/system/al_Config.h"

#ifdef _LIBCPP_VERSION
	#include <unordered_map>
#else
	#include <tr1/unordered_map>
#endif
#include <map>
#include <vector>
#include "allocore/types/al_Buffer.hpp"
#include "allocore/graphics/al_Graphics.hpp"

namespace al{

/// Isosurface generated using marching cubes
class Isosurface : public Mesh {
public:

	struct EdgeVertex {
		Vec3i pos;			// cell coordinates
		Vec3i corners[2];	// edge corners as offsets from cell coordinates
		float x, y, z;		// vertex position
		float mu;			// fraction along edge of vertex

		/// Returns position of edge vertices
		Vec3i edgePos(int i) const { return pos + corners[i]; }
	};

	struct EdgeTriangle {
		int edgeIDs[3];
	};

	struct VertexAction {
		virtual ~VertexAction(){}
		virtual void operator()(const Isosurface::EdgeVertex& v, Isosurface& s) = 0;
	};

	struct NoVertexAction : public VertexAction{
		virtual void operator()(const EdgeVertex& v, Isosurface& s){}
	};

	static NoVertexAction noVertexAction;

	/// @param[in] level	value to construct surface on
	/// @param[in] action	user defined functor called upon adding a new edge vertex
	Isosurface(float level=0, VertexAction& action = noVertexAction);

	virtual ~Isosurface();

	/// Get a field dimension
	int fieldDim(int i) const { return mNF[i]; }

	/// Get isolevel
	float level() const { return mIsolevel; }

	/// Returns true if a valid surface has been generated
	bool validSurface() const { return mValidSurface; }

	/// Gets the length, width, and height of the isosurface volume

	/// \returns true upon success and false if the surface is not valid
	///
	bool volumeLengths(double& volLengthX, double& volLengthY, double& volLengthZ) const;

	// Get unique identifier of 3d position indices
	int posID(int ix, int iy, int iz) const { return ix + mNF[0] * (iy + mNF[1] * iz); }

	template <class VEC3I>
	int posID(const VEC3I& i3) const { return posID(i3[0], i3[1], i3[2]); }

	// Get unique identifier of cell
	int cellID(int ix, int iy, int iz) const{ return 3*posID(ix,iy,iz); }

	// Get unique identifier of edge
	int edgeID(int cellID, int edgeNo) const{ return cellID + mEdgeIDOffsets[edgeNo]; }

	/// Set individual dimensions of the scalar field
	Isosurface& fieldDims(int nx, int ny, int nz);

	/// Set all dimensions of the scalar field
	Isosurface& fieldDims(int n){ return fieldDims(n,n,n); }

	/// Set individual lengths of cell
	Isosurface& cellLengths(double dx, double dy, double dz);

	/// Set all lengths of cell
	Isosurface& cellLengths(double v){ return cellLengths(v,v,v); }

	/// Set isolevel
	Isosurface& level(float v){ mIsolevel=v; return *this; }

	/// Set whether to compute normals
	Isosurface& normals(bool v){ mComputeNormals=v; return *this; }

	/// Set whether to normalize normals (if being computed)
	Isosurface& normalize(bool v){ mNormalize=v; return *this; }

	/// Begin cell-at-a-time mode
	void begin();

	/// End cell-at-a-time mode
	void end();

	/// Clear the isosurface
	void clear();

	/// Add a cell from a scalar field

	/// This should be called in between calls to begin() and end().
	///
	template <class T>
	void addCell(
		int ix, int iy, int iz,
		const T& xyz, const T& Xyz,
		const T& xYz, const T& XYz,
		const T& xyZ, const T& XyZ,
		const T& xYZ, const T& XYZ
	){
		int inds[3] = { ix, iy, iz };
		const float vals[8] = { xyz, Xyz, xYz, XYz, xyZ, XyZ, xYZ, XYZ };
		addCell(inds, vals);
	}

	/// Add a cell from a scalar field
	void addCell(const int * indices3, const float * values8);

	/// Generate isosurface from scalar field
	template <class T>
	void generate(const T * scalarField);

	/// Generate isosurface from scalar field

	/// The total number of elements in the field is expected to be nX*nY*nZ.
	/// The field elements are located at the corners of the cuboidal cells used
	/// to generate the surface. Thus, the surface is evaluated on a total of
	/// (nX-1)*(nY-1)*(nZ-1) cells.
	template <class T>
	void generate(const T * scalarField, int nX, int nY, int nZ, float cellLengthX, float cellLengthY, float cellLengthZ){
		fieldDims(nX, nY, nZ);
		cellLengths(cellLengthX, cellLengthY, cellLengthZ);
		generate(scalarField);
	}

	template <class T>
	void generate(const T * scalarField, int n, float cellLength){
		generate(scalarField, n,n,n, cellLength,cellLength,cellLength);
	}

	/// A variation that shifts & wraps all the cells by integer amounts
	template <class T>
	void generate_shifted(const T * scalarField, const int sx, const int sy, const int sz);

	void vertexAction(VertexAction& a){ mVertexAction = &a; }

	const bool inBox() const { return mInBox; }

	/// Set whether isosurface is assumed to fit snugly within a box

	/// Setting this to true will speed up extraction when the isosurface
	/// is mostly dense and box shaped, i.e., a rectangular cuboid. If the
	/// isosurface is to be computed on sparse or irregularly shaped grid, then
	/// it is recommended to set this to false to save memory.
	Isosurface& inBox(bool v);

protected:

	struct IsosurfaceHashInt{
		size_t operator()(int v) const { return v; }
	//	size_t operator()(int v) const { return v*2654435761UL; }
	};

	#ifdef _LIBCPP_VERSION
	typedef std::unordered_map<int, int, IsosurfaceHashInt> EdgeToVertex;
	#else
	typedef std::tr1::unordered_map<int, int, IsosurfaceHashInt> EdgeToVertex;
	#endif
//	typedef std::map<int, VertexData> EdgeToVertex;

	EdgeToVertex mEdgeToVertex;					// map from edge ID to vertex
	al::Buffer<EdgeTriangle> mEdgeTriangles;	// surface triangles in terms of edge IDs

	std::vector<int> mEdgeToVertexArray;
//	al::Buffer<int> mTempEdges;

	double mL[3];				// cell length in x, y, and z directions
	int mNF[3];					// number of field points in x, y, and z directions
	int mEdgeIDOffsets[12];		// used to obtain edge ID from vertex ID and edge number
	float mIsolevel;			// isosurface level
	VertexAction * mVertexAction;
	bool mValidSurface;			// indicates whether a valid surface is present
	bool mComputeNormals;		// whether to compute normals
	bool mNormalize;			// whether to normalize normals
	bool mInBox;

	EdgeVertex calcIntersection(int nX, int nY, int nZ, int nEdgeNo, const float * vals) const;
	void addEdgeVertex(int x, int y, int z, int cellID, int edge, const float * vals);

	void compressTriangles();
};

// Implementation ______________________________________________________________

template <class T>
void Isosurface::generate(const T * vals){
	inBox(true);
	begin();

	int Nx = mNF[0];
	int Nxy = Nx*mNF[1];

	// iterate through cubes (not field points)
	//for(int z=0; z < mNF[2]-1; ++z){
	// support transparency (assumes higher indices are farther away)
	for(int z=mNF[2]-2; z>=0; --z){
		int z0 = z   *Nxy;
		int z1 =(z+1)*Nxy;
		for(int y=0; y < mNF[1]-1; ++y){
			int y0 = y   *Nx;
			int y1 =(y+1)*Nx;

			int z0y0 = z0+y0;
			int z0y1 = z0+y1;
			int z1y0 = z1+y0;
			int z1y1 = z1+y1;

			int z0y0_1 = z0y0+1;
			int z0y1_1 = z0y1+1;
			int z1y0_1 = z1y0+1;
			int z1y1_1 = z1y1+1;

			for(int x=0; x < mNF[0]-1; ++x){

				float v8[] = {
					vals[z0y0 + x], vals[z0y0_1 + x],
					vals[z0y1 + x], vals[z0y1_1 + x],
					vals[z1y0 + x], vals[z1y0_1 + x],
					vals[z1y1 + x], vals[z1y1_1 + x]
				};

				int i3[] = {x,y,z};

				addCell(i3,	v8);
			}
		}
	}

	end();
}

// generate but shift & wrap the cubes by an integer amount:
template <class T>
void Isosurface::generate_shifted(const T * vals, const int sx, const int sy, const int sz){
	inBox(true);
	begin();

	int Nx = mNF[0];
	int Nxy = Nx*mNF[1];

	// iterate through cubes (not field points)
	//for(int z=0; z < mNF[2]-1; ++z){
	// support transparency (assumes higher indices are farther away)
	for(int z=mNF[2]-2; z>=0; --z){
		int z0 = z   *Nxy;
		int z1 =(z+1)*Nxy;
		for(int y=0; y < mNF[1]-1; ++y){
			int y0 = y   *Nx;
			int y1 =(y+1)*Nx;

			int z0y0 = z0+y0;
			int z0y1 = z0+y1;
			int z1y0 = z1+y0;
			int z1y1 = z1+y1;

			int z0y0_1 = z0y0+1;
			int z0y1_1 = z0y1+1;
			int z1y0_1 = z1y0+1;
			int z1y1_1 = z1y1+1;

			for(int x=0; x < mNF[0]-1; ++x){

				float v8[] = {
					vals[z0y0 + x], vals[z0y0_1 + x],
					vals[z0y1 + x], vals[z0y1_1 + x],
					vals[z1y0 + x], vals[z1y0_1 + x],
					vals[z1y1 + x], vals[z1y1_1 + x]
				};

				int i3[] = {x, y, z};

				addCell(i3,	v8);
			}
		}
	}

	end();
}

} // al::

#endif
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "sysdef.h"
#include "csutil/scanstr.h"

int ScanStr (char* in, char* format, ...)
{
  va_list arg;
  va_start (arg, format);

  int num = 0;
  in += strspn (in, " \t\n\f");

  while (*format)
  {
    if (*format == '%')
    {
      format++;
      switch (*format)
      {
        case 'd':
	{
	  int* a = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  *a = atoi (in);
	  in += strspn (in, "0123456789+- \t\n\f");
	  num++;
	  break;
	}
	case 'D':
	{
	  int i;
	  int* list = va_arg (arg, int*);
	  int* nr = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  i = 0;
	  while ((*in >= '0' && *in <= '9') || *in == '+' || *in == '-')
	  {
	    list[i++] = atoi (in);
	    in += strspn (in, "0123456789+-");
	    in += strspn (in, " \t\n\f");
	    if (*in != ',') break;
	    in++;
	    in += strspn (in, " \t\n\f");
	  }
	  *nr = i;
	  num++;
	  break;
	}
        case 'b':
	{
	  int* a = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  char* in2 = in + strspn (in, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
	  int l = (int)(in2-in);
	  *a = !strncasecmp (in, "yes", l) || !strncasecmp (in, "true", l) || !strncasecmp (in, "on", l) ||
	  	!strncasecmp (in, "1", l);
	  in = in2 + strspn (in2, " \t\n\f");
	  num++;
	  break;
	}
	case 'f':
	{
	  float* a = va_arg (arg, float*);
	  in += strspn (in, " \t\n\f");
	  *a = atof (in);
	  in += strspn (in, "0123456789.eE+- \t\n\f");
	  num++;
	  break;
	}
	case 'F':
	{
	  int i;
	  float* list = va_arg (arg, float*);
	  int* nr = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  i = 0;
	  while ((*in >= '0' && *in <= '9') || *in == '.' || *in == '+' || *in == '-' || *in == 'e' || *in == 'E')
	  {
	    list[i++] = atof (in);
	    in += strspn (in, "0123456789.eE+-");
	    in += strspn (in, " \t\n\f");
	    if (*in != ',') break;
	    in++;
	    in += strspn (in, " \t\n\f");
	  }
	  *nr = i;
	  num++;
	  break;
	}
	case 's':
	{
	  char* a = va_arg (arg, char*);
	  in += strspn (in, " \t\n\f");
	  if (*in == '\'')
	  {
	    in++;
	    char* in2 = strchr (in, '\'');
	    strncpy (a, in, (int)(in2-in));
	    a[(int)(in2-in)] = 0;
	    in = in2+1;
	  }
	  else
	  {
	    char* in2 = in + strspn (in, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789");
	    strncpy (a, in, (int)(in2-in));
	    a[(int)(in2-in)] = 0;
	    in = in2;
	  }
	  in += strspn (in, " \t\n\f");
	  num++;
	  break;
	}
      }
      if (*format) format++;
    }
    else if (*format == ' ') { format++; in += strspn (in, " \t\n\f"); }
    else if (*in == *format) { in++; format++; }
    else { num = -1; break; }
  }

  va_end (arg);

  return num;
}
<commit_msg>Fixed ScanStr() so that '.' is also in string.<commit_after>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "sysdef.h"
#include "csutil/scanstr.h"

int ScanStr (char* in, char* format, ...)
{
  va_list arg;
  va_start (arg, format);

  int num = 0;
  in += strspn (in, " \t\n\f");

  while (*format)
  {
    if (*format == '%')
    {
      format++;
      switch (*format)
      {
        case 'd':
	{
	  int* a = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  *a = atoi (in);
	  in += strspn (in, "0123456789+- \t\n\f");
	  num++;
	  break;
	}
	case 'D':
	{
	  int i;
	  int* list = va_arg (arg, int*);
	  int* nr = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  i = 0;
	  while ((*in >= '0' && *in <= '9') || *in == '+' || *in == '-')
	  {
	    list[i++] = atoi (in);
	    in += strspn (in, "0123456789+-");
	    in += strspn (in, " \t\n\f");
	    if (*in != ',') break;
	    in++;
	    in += strspn (in, " \t\n\f");
	  }
	  *nr = i;
	  num++;
	  break;
	}
        case 'b':
	{
	  int* a = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  char* in2 = in + strspn (in, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
	  int l = (int)(in2-in);
	  *a = !strncasecmp (in, "yes", l) || !strncasecmp (in, "true", l) || !strncasecmp (in, "on", l) ||
	  	!strncasecmp (in, "1", l);
	  in = in2 + strspn (in2, " \t\n\f");
	  num++;
	  break;
	}
	case 'f':
	{
	  float* a = va_arg (arg, float*);
	  in += strspn (in, " \t\n\f");
	  *a = atof (in);
	  in += strspn (in, "0123456789.eE+- \t\n\f");
	  num++;
	  break;
	}
	case 'F':
	{
	  int i;
	  float* list = va_arg (arg, float*);
	  int* nr = va_arg (arg, int*);
	  in += strspn (in, " \t\n\f");
	  i = 0;
	  while ((*in >= '0' && *in <= '9') || *in == '.' || *in == '+' || *in == '-' || *in == 'e' || *in == 'E')
	  {
	    list[i++] = atof (in);
	    in += strspn (in, "0123456789.eE+-");
	    in += strspn (in, " \t\n\f");
	    if (*in != ',') break;
	    in++;
	    in += strspn (in, " \t\n\f");
	  }
	  *nr = i;
	  num++;
	  break;
	}
	case 's':
	{
	  char* a = va_arg (arg, char*);
	  in += strspn (in, " \t\n\f");
	  if (*in == '\'')
	  {
	    in++;
	    char* in2 = strchr (in, '\'');
	    strncpy (a, in, (int)(in2-in));
	    a[(int)(in2-in)] = 0;
	    in = in2+1;
	  }
	  else
	  {
	    char* in2 = in + strspn (in, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789.");
	    strncpy (a, in, (int)(in2-in));
	    a[(int)(in2-in)] = 0;
	    in = in2;
	  }
	  in += strspn (in, " \t\n\f");
	  num++;
	  break;
	}
      }
      if (*format) format++;
    }
    else if (*format == ' ') { format++; in += strspn (in, " \t\n\f"); }
    else if (*in == *format) { in++; format++; }
    else { num = -1; break; }
  }

  va_end (arg);

  return num;
}
<|endoftext|>


<commit_before>/*
  BelaCsound.cpp:

  Copyright (C) 2017 V Lazzarini

  This file is part of Csound.

  The Csound Library is free software; you can redistribute it
  and/or modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Csound is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/
#include <Bela.h>
#include <Midi.h>
#include <csound/csound.hpp>
#include <csound/plugin.h>
#include <vector>
#include <sstream>

#define ANCHNS 8

static int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiInDevice(CSOUND *csound, void *userData);
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf,
			int nbytes);
static int OpenMidiOutDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiOutDevice(CSOUND *csound, void *userData);
static int WriteMidiData(CSOUND *csound, void *userData, const unsigned char *mbuf,
			 int nbytes);

/** DigiIn opcode
    ksig digiInBela ipin
    asig digiInBela ipin
*/
struct DigiIn : csnd::Plugin<1, 1> {
  int pin;
  int fcount;
  int frms;
  BelaContext *context;

  int init() {
    pin = (int) inargs[0];
    if(pin < 0 ) pin = 0;
    if(pin > 15) pin = 15;
    context = (BelaContext *) csound->host_data();
    pinMode(context,0,pin,0);
    fcount = 0;
    frms = context->digitalFrames;
    return OK;
  }

  int kperf() {
    outargs[0] = digitalRead(context,fcount,pin);
    fcount += nsmps;
    fcount %= frms;
    return OK;
  }

  int aperf() {
    csnd::AudioSig out(this, outargs(0));
    int cnt = fcount;
    for (auto &s : out) {
      s = digitalRead(context,cnt,pin);
      if(cnt == frms - 1) cnt = 0;
      else cnt++;
    }
    fcount = cnt;
  }
};

/** DigiOut opcode
    digiOutBela ksig,ipin
    digiOutBela asig,ipin
*/
struct DigiOut : csnd::Plugin<0, 2> {
  int pin;
  int fcount;
  int frms;
  BelaContext *context;

  int init() {
    pin = (int) inargs[1];
    if(pin < 0 ) pin = 0;
    if(pin > 15) pin = 15;
    context = (BelaContext *) csound->host_data();
    pinMode(context,0,pin,1);
    fcount = 0;
    frms = context->digitalFrames;
    return OK;
  }

  int kperf() {
    digitalWrite(context,fcount,pin,inargs[0]);
    fcount += nsmps;
    fcount %= frms;
    return OK;
  }

  int aperf() {
    csnd::AudioSig in(this, inargs(0));
    int cnt = fcount;
    for (auto s : in) {
      digitalWriteOnce(context,cnt,pin,s);
      if(cnt == frms - 1) cnt = 0;
      else cnt++;
    }
    fcount = cnt;
  }
};

struct CsChan {
  std::vector<MYFLT> data;
  std::stringstream name;
};

struct CsData {
  Csound *csound;
  int blocksize;
  int res;
  int count;
  CsChan channel[ANCHNS];
  CsChan ochannel[ANCHNS];
};

static CsData gCsData;
static Midi gMidi;

bool setup(BelaContext *context, void *Data)
{
  Csound *csound;
  const char *csdfile = "my.csd"; /* CSD name */
  const char *midiDev = "-Mhw:1,0,0"; /* MIDI IN device */
  const char *midiOutDev = "-Qhw:1,0,0"; /* MIDI OUT device */
  const char *args[] = { "csound", csdfile, "-iadc", "-odac", "-+rtaudio=null",
			 "--realtime", "--daemon", midiDev, midiOutDev };
  int numArgs = (int) (sizeof(args)/sizeof(char *));

  if(context->audioInChannels != context->audioOutChannels) {
    printf("Error: number of audio inputs != number of audio outputs.\n");
    return false;
  }

  if(context->analogInChannels != context->analogOutChannels) {
    printf("Error: number of analog inputs != number of analog outputs.\n");
    return false;
  }

  /* set up Csound */
  csound = new Csound();
  gCsData.csound = csound;
  csound->SetHostData((void *) context);
  csound->SetHostImplementedAudioIO(1,0);
  csound->SetHostImplementedMIDIIO(1);
  csound->SetExternalMidiInOpenCallback(OpenMidiInDevice);
  csound->SetExternalMidiReadCallback(ReadMidiData);
  csound->SetExternalMidiInCloseCallback(CloseMidiInDevice);
  csound->SetExternalMidiOutOpenCallback(OpenMidiOutDevice);
  csound->SetExternalMidiWriteCallback(WriteMidiData);
  csound->SetExternalMidiOutCloseCallback(CloseMidiOutDevice);
  /* set up digi opcodes */
  if(csnd::plugin<DigiIn>((csnd::Csound *) csound->GetCsound(), "digiInBela" , "k",
			  "i", csnd::thread::ik) != 0)
    printf("Warning: could not add digiInBela k-rate opcode\n");

  if(csnd::plugin<DigiIn>((csnd::Csound *) csound->GetCsound(), "digiInBela" , "a",
			  "i", csnd::thread::ia) != 0)
    printf("Warning: could not add digiInBela a-rate opcode\n");

  if(csnd::plugin<DigiOut>((csnd::Csound *) csound->GetCsound(), "digiOutBela" , "",
			   "ki", csnd::thread::ik) != 0)
    printf("Warning: could not add digiOutBela k-rate opcode\n");

  if(csnd::plugin<DigiOut>((csnd::Csound *) csound->GetCsound(), "digiOutBela" , "",
			   "ai", csnd::thread::ia) != 0)
    printf("Warning: could not add digiOutBela a-rate opcode\n");

  if((gCsData.res = csound->Compile(numArgs, args)) != 0) {
    printf("Error: Csound could not compile CSD file.\n");
    return false;
  }
  gCsData.blocksize = csound->GetKsmps()*csound->GetNchnls();
  gCsData.count = 0;

  /* set up the channels */
  for(int i=0; i < ANCHNS; i++) {
    gCsData.channel[i].data.resize(csound->GetKsmps());
    gCsData.channel[i].name << "analogIn" << i+1;
    gCsData.ochannel[i].data.resize(csound->GetKsmps());
    gCsData.ochannel[i].name << "analogOut" << i+1;
  }

  return true;
}

void render(BelaContext *context, void *Data)
{
  if(gCsData.res == 0) {
    int n,i,k,count, frmcount,blocksize,res;
    Csound *csound = gCsData.csound;
    MYFLT scal = csound->Get0dBFS();
    MYFLT* audioIn = csound->GetSpin();
    MYFLT* audioOut = csound->GetSpout();
    int nchnls = csound->GetNchnls();
    int chns = nchnls < context->audioOutChannels ?
      nchnls : context->audioOutChannels;
    int an_chns = context->analogInChannels > ANCHNS ?
      ANCHNS : context->analogInChannels;
    CsChan *channel = &(gCsData.channel[0]);
    CsChan *ochannel = &(gCsData.ochannel[0]);
    float frm = 0.f, incr = ((float) context->analogFrames)/context->audioFrames;
    count = gCsData.count;
    blocksize = gCsData.blocksize;

    /* processing loop */
    for(n = 0; n < context->audioFrames; n++, frm+=incr, count+=nchnls){
      if(count == blocksize) {
	/* set the channels */
	for(i = 0; i < an_chns; i++) {
          csound->SetChannel(channel[i].name.str().c_str(),
			     &(channel[i].data[0]));
	  csound->GetAudioChannel(ochannel[i].name.str().c_str(),
				  &(ochannel[i].data[0]));
	}
	/* run csound */
	if((res = csound->PerformKsmps()) == 0) count = 0;
	else break;
      }
      /* read/write audio data */
      for(i = 0; i < chns; i++){
	audioIn[count+i] = audioRead(context,n,i);
	audioWrite(context,n,i,audioOut[count+i]/scal);
      }
      /* read analogue data
         analogue frame pos frm gets incremented according to the
         ratio analogFrames/audioFrames.
      */
      frmcount = count/nchnls;
      for(i = 0; i < an_chns; i++) {
	k = (int) frm;
        channel[i].data[frmcount] = analogRead(context,k,i);
	analogWriteOnce(context,k,i,ochannel[i].data[frmcount]);
      }
    }
    gCsData.res = res;
    gCsData.count = count;
  }
}

void cleanup(BelaContext *context, void *Data)
{
  delete gCsData.csound;
}

/** MIDI Input functions
 */
int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev) {
  if(gMidi.readFrom(dev) == 1) {
    gMidi.enableParser(false);
    *userData = (void *) &gMidi;
    return 0;
  }
  csoundMessage(csound, "Could not open Midi in device %s", dev);
  return -1;
}

int CloseMidiInDevice(CSOUND *csound, void *userData) {
  return 0;
}

int ReadMidiData(CSOUND *csound, void *userData,
		 unsigned char *mbuf, int nbytes) {
  int n = 0, byte;
  if(userData) {
    Midi *midi = (Midi *) userData;

    while((byte = midi->getInput()) >= 0) {
      *mbuf++ = (unsigned char) byte;
      if(++n == nbytes) break;
    }
    return n;
  }
  return 0;
}

int OpenMidiOutDevice(CSOUND *csound, void **userData, const char *dev) {
  if(gMidi.writeTo(dev) == 1) {
    gMidi.enableParser(false);
    *userData = (void *) &gMidi;
    return 0;
  }
  csoundMessage(csound, "Could not open Midi out device %s", dev);
  return -1;
}

int CloseMidiOutDevice(CSOUND *csound, void *userData) {
  return 0;
}

int WriteMidiData(CSOUND *csound, void *userData,
		  const unsigned char *mbuf, int nbytes) {
  if(userData) {
    Midi *midi = (Midi *) userData;
    if(midi->writeOutput((midi_byte_t *)mbuf, nbytes) > 0) return nbytes;
    return 0;
  }
  return 0;
}
<commit_msg>init_done<commit_after>/*
  BelaCsound.cpp:

  Copyright (C) 2017 V Lazzarini

  This file is part of Csound.

  The Csound Library is free software; you can redistribute it
  and/or modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Csound is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/
#include <Bela.h>
#include <Midi.h>
#include <csound/csound.hpp>
#include <csound/plugin.h>
#include <vector>
#include <sstream>

#define ANCHNS 8

static int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiInDevice(CSOUND *csound, void *userData);
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf,
			int nbytes);
static int OpenMidiOutDevice(CSOUND *csound, void **userData, const char *dev);
static int CloseMidiOutDevice(CSOUND *csound, void *userData);
static int WriteMidiData(CSOUND *csound, void *userData, const unsigned char *mbuf,
			 int nbytes);

/** DigiIn opcode
    ksig digiInBela ipin
    asig digiInBela ipin
*/
struct DigiIn : csnd::Plugin<1, 1> {
  int pin;
  int fcount;
  int frms;
  init init_done;
  BelaContext *context;

  int init() {
    pin = (int) inargs[0];
    if(pin < 0 ) pin = 0;
    if(pin > 15) pin = 15;
    context = (BelaContext *) csound->host_data();
    fcount = 0;
    init_done = 0;
    frms = context->digitalFrames;
    return OK;
  }

  int kperf() {
   if(!init_done) {
      pinMode(context,0,pin,0);
      init_done = 1;
    }
    outargs[0] = (MYFLT) digitalRead(context,fcount,pin);
    fcount += nsmps;
    fcount %= frms;
    return OK;
  }

  int aperf() {
    csnd::AudioSig out(this, outargs(0));
    int cnt = fcount;
    if(!init_done) {
      pinMode(context,0,pin,0);
      init_done = 1;
    }
    for (auto &s : out) {
      s = (MYFLT) digitalRead(context,cnt,pin);
      if(cnt == frms - 1) cnt = 0;
      else cnt++;
    }
    fcount = cnt;
    return OK;
  }
};

/** DigiOut opcode
    digiOutBela ksig,ipin
    digiOutBela asig,ipin
*/
struct DigiOut : csnd::Plugin<0, 2> {
  int pin;
  int fcount;
  int frms;
  int init_done;
  BelaContext *context;

  int init() {
    pin = (int) inargs[1];
    if(pin < 0 ) pin = 0;
    if(pin > 15) pin = 15;
    context = (BelaContext *) csound->host_data();
    init_done = 0;
    fcount = 0;
    frms = context->digitalFrames;
    return OK;
  }

  int kperf() {
    if(!init_done) {
      pinMode(context,0,pin,1);
      init_done = 1;
    }
    digitalWrite(context,fcount,pin,(inargs[0] > 0.0 ? 1 : 0));
    fcount += nsmps;
    fcount %= frms;
    return OK;
  }

  int aperf() {
    csnd::AudioSig in(this, inargs(0));
    int cnt = fcount;
    if(!init_done) {
      pinMode(context,0,pin,1);
      init_done = 1;
    }
    for (auto s : in) {
      digitalWriteOnce(context,cnt,pin, (s > 0.0 ? 1 : 0));
      if(cnt == frms - 1) cnt = 0;
      else cnt++;
    }
    fcount = cnt;
    return OK;
  }
};

struct CsChan {
  std::vector<MYFLT> data;
  std::stringstream name;
};

struct CsData {
  Csound *csound;
  int blocksize;
  int res;
  int count;
  CsChan channel[ANCHNS];
  CsChan ochannel[ANCHNS];
};

static CsData gCsData;
static Midi gMidi;

bool setup(BelaContext *context, void *Data)
{
  Csound *csound;
  const char *csdfile = "my.csd"; /* CSD name */
  const char *midiDev = "-Mhw:1,0,0"; /* MIDI IN device */
  const char *midiOutDev = "-Qhw:1,0,0"; /* MIDI OUT device */
  const char *args[] = { "csound", csdfile, "-iadc", "-odac", "-+rtaudio=null",
			 "--realtime", "--daemon", midiDev, midiOutDev };
  int numArgs = (int) (sizeof(args)/sizeof(char *));

  if(context->audioInChannels != context->audioOutChannels) {
    printf("Error: number of audio inputs != number of audio outputs.\n");
    return false;
  }

  if(context->analogInChannels != context->analogOutChannels) {
    printf("Error: number of analog inputs != number of analog outputs.\n");
    return false;
  }

  /* set up Csound */
  csound = new Csound();
  gCsData.csound = csound;
  csound->SetHostData((void *) context);
  csound->SetHostImplementedAudioIO(1,0);
  csound->SetHostImplementedMIDIIO(1);
  csound->SetExternalMidiInOpenCallback(OpenMidiInDevice);
  csound->SetExternalMidiReadCallback(ReadMidiData);
  csound->SetExternalMidiInCloseCallback(CloseMidiInDevice);
  csound->SetExternalMidiOutOpenCallback(OpenMidiOutDevice);
  csound->SetExternalMidiWriteCallback(WriteMidiData);
  csound->SetExternalMidiOutCloseCallback(CloseMidiOutDevice);
  /* set up digi opcodes */
  if(csnd::plugin<DigiIn>((csnd::Csound *) csound->GetCsound(), "digiInBela" , "k",
			  "i", csnd::thread::ik) != 0)
    printf("Warning: could not add digiInBela k-rate opcode\n");

  if(csnd::plugin<DigiIn>((csnd::Csound *) csound->GetCsound(), "digiInBela" , "a",
			  "i", csnd::thread::ia) != 0)
    printf("Warning: could not add digiInBela a-rate opcode\n");

  if(csnd::plugin<DigiOut>((csnd::Csound *) csound->GetCsound(), "digiOutBela" , "",
			   "ki", csnd::thread::ik) != 0)
    printf("Warning: could not add digiOutBela k-rate opcode\n");

  if(csnd::plugin<DigiOut>((csnd::Csound *) csound->GetCsound(), "digiOutBela" , "",
			   "ai", csnd::thread::ia) != 0)
    printf("Warning: could not add digiOutBela a-rate opcode\n");

  if((gCsData.res = csound->Compile(numArgs, args)) != 0) {
    printf("Error: Csound could not compile CSD file.\n");
    return false;
  }
  gCsData.blocksize = csound->GetKsmps()*csound->GetNchnls();
  gCsData.count = 0;

  /* set up the channels */
  for(int i=0; i < ANCHNS; i++) {
    gCsData.channel[i].data.resize(csound->GetKsmps());
    gCsData.channel[i].name << "analogIn" << i+1;
    gCsData.ochannel[i].data.resize(csound->GetKsmps());
    gCsData.ochannel[i].name << "analogOut" << i+1;
  }

  return true;
}

void render(BelaContext *context, void *Data)
{
  if(gCsData.res == 0) {
    int n,i,k,count, frmcount,blocksize,res;
    Csound *csound = gCsData.csound;
    MYFLT scal = csound->Get0dBFS();
    MYFLT* audioIn = csound->GetSpin();
    MYFLT* audioOut = csound->GetSpout();
    int nchnls = csound->GetNchnls();
    int chns = nchnls < context->audioOutChannels ?
      nchnls : context->audioOutChannels;
    int an_chns = context->analogInChannels > ANCHNS ?
      ANCHNS : context->analogInChannels;
    CsChan *channel = &(gCsData.channel[0]);
    CsChan *ochannel = &(gCsData.ochannel[0]);
    float frm = 0.f, incr = ((float) context->analogFrames)/context->audioFrames;
    count = gCsData.count;
    blocksize = gCsData.blocksize;

    /* processing loop */
    for(n = 0; n < context->audioFrames; n++, frm+=incr, count+=nchnls){
      if(count == blocksize) {
	/* set the channels */
	for(i = 0; i < an_chns; i++) {
          csound->SetChannel(channel[i].name.str().c_str(),
			     &(channel[i].data[0]));
	  csound->GetAudioChannel(ochannel[i].name.str().c_str(),
				  &(ochannel[i].data[0]));
	}
	/* run csound */
	if((res = csound->PerformKsmps()) == 0) count = 0;
	else break;
      }
      /* read/write audio data */
      for(i = 0; i < chns; i++){
	audioIn[count+i] = audioRead(context,n,i);
	audioWrite(context,n,i,audioOut[count+i]/scal);
      }
      /* read analogue data
         analogue frame pos frm gets incremented according to the
         ratio analogFrames/audioFrames.
      */
      frmcount = count/nchnls;
      for(i = 0; i < an_chns; i++) {
	k = (int) frm;
        channel[i].data[frmcount] = analogRead(context,k,i);
	analogWriteOnce(context,k,i,ochannel[i].data[frmcount]);
      }
    }
    gCsData.res = res;
    gCsData.count = count;
  }
}

void cleanup(BelaContext *context, void *Data)
{
  delete gCsData.csound;
}

/** MIDI Input functions
 */
int OpenMidiInDevice(CSOUND *csound, void **userData, const char *dev) {
  if(gMidi.readFrom(dev) == 1) {
    gMidi.enableParser(false);
    *userData = (void *) &gMidi;
    return 0;
  }
  csoundMessage(csound, "Could not open Midi in device %s", dev);
  return -1;
}

int CloseMidiInDevice(CSOUND *csound, void *userData) {
  return 0;
}

int ReadMidiData(CSOUND *csound, void *userData,
		 unsigned char *mbuf, int nbytes) {
  int n = 0, byte;
  if(userData) {
    Midi *midi = (Midi *) userData;

    while((byte = midi->getInput()) >= 0) {
      *mbuf++ = (unsigned char) byte;
      if(++n == nbytes) break;
    }
    return n;
  }
  return 0;
}

int OpenMidiOutDevice(CSOUND *csound, void **userData, const char *dev) {
  if(gMidi.writeTo(dev) == 1) {
    gMidi.enableParser(false);
    *userData = (void *) &gMidi;
    return 0;
  }
  csoundMessage(csound, "Could not open Midi out device %s", dev);
  return -1;
}

int CloseMidiOutDevice(CSOUND *csound, void *userData) {
  return 0;
}

int WriteMidiData(CSOUND *csound, void *userData,
		  const unsigned char *mbuf, int nbytes) {
  if(userData) {
    Midi *midi = (Midi *) userData;
    if(midi->writeOutput((midi_byte_t *)mbuf, nbytes) > 0) return nbytes;
    return 0;
  }
  return 0;
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Adam Bloniarz, Jonathan Terhorst, Ameet Talwalkar
 *
 * 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 <tclap/CmdLine.h>
#include "api/BamReader.h"

using namespace std;
using namespace BamTools;

string get_cigar(vector<CigarOp> cig_ops) {

  string cigar;

  for (auto cig_op : cig_ops) {
    cigar += to_string(cig_op.Length);
    cigar += cig_op.Type;
  }
  return cigar;
}

int main(int argc, char** argv) {

  /* Command line arguments:
   *  1) Bamfile
   *  2) Contig
   *  3) Start
   *  4) End
   */

  try {
  TCLAP::CmdLine cmd("Bamdump - dump the contents of a bam file to stdout, to be piped to CAGe");

  TCLAP::UnlabeledValueArg<string> bamfile_arg("bamfile", "bam file", true, "", "bamfile", cmd);
  TCLAP::UnlabeledValueArg<string> contig_arg("contig", "contig name", true, "", "contig", cmd);
  TCLAP::UnlabeledValueArg<int> start_arg("start", "start position", true, 0, "start", cmd);
  TCLAP::UnlabeledValueArg<int> end_arg("end", "end position", true, 0, "end", cmd);
  cmd.parse(argc, argv);

  BamReader reader;
  string bamfile = bamfile_arg.getValue();
  if (!reader.Open(bamfile)) {
    throw runtime_error(string("Unable to open bam file ") + bamfile);
  }
  if (!reader.OpenIndex(bamfile + ".bai")) {
    throw runtime_error(string("Unable to open bam file ") + bamfile + ".bai");
  }

  string contig = contig_arg.getValue();
  int refID = reader.GetReferenceID(contig);

  int start = start_arg.getValue();
  int end = end_arg.getValue();

  reader.SetRegion(refID, start, refID, end);

  BamAlignment al;

  while (reader.GetNextAlignment(al)) {
    printf("%i %s %s %s %i %i\n", al.Position, al.QueryBases.c_str(), get_cigar(al.CigarData).c_str(), al.Qualities.c_str(), al.MapQuality, al.IsReverseStrand() ? 1 : 0);
  }

  reader.Close();
  } catch (exception& e) {
    cerr << e.what() << endl;
    return 1;
  }
  return 0;
}
<commit_msg>Fixed indentation<commit_after>/**
 * Copyright 2015 Adam Bloniarz, Jonathan Terhorst, Ameet Talwalkar
 *
 * 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 <tclap/CmdLine.h>
#include "api/BamReader.h"

using namespace std;
using namespace BamTools;

string get_cigar(vector<CigarOp> cig_ops) {

  string cigar;

  for (auto cig_op : cig_ops) {
    cigar += to_string(cig_op.Length);
    cigar += cig_op.Type;
  }
  return cigar;
}

int main(int argc, char** argv) {

  /* Command line arguments:
   *  1) Bamfile
   *  2) Contig
   *  3) Start
   *  4) End
   */

  try {
    TCLAP::CmdLine cmd("Bamdump - dump the contents of a bam file to stdout, to be piped to CAGe");

    TCLAP::UnlabeledValueArg<string> bamfile_arg("bamfile", "bam file", true, "", "bamfile", cmd);
    TCLAP::UnlabeledValueArg<string> contig_arg("contig", "contig name", true, "", "contig", cmd);
    TCLAP::UnlabeledValueArg<int> start_arg("start", "start position", true, 0, "start", cmd);
    TCLAP::UnlabeledValueArg<int> end_arg("end", "end position", true, 0, "end", cmd);
    cmd.parse(argc, argv);

    BamReader reader;
    string bamfile = bamfile_arg.getValue();
    if (!reader.Open(bamfile)) {
      throw runtime_error(string("Unable to open bam file ") + bamfile);
    }
    if (!reader.OpenIndex(bamfile + ".bai")) {
      throw runtime_error(string("Unable to open bam file ") + bamfile + ".bai");
    }

    string contig = contig_arg.getValue();
    int refID = reader.GetReferenceID(contig);

    int start = start_arg.getValue();
    int end = end_arg.getValue();

    reader.SetRegion(refID, start, refID, end);

    BamAlignment al;

    while (reader.GetNextAlignment(al)) {
      printf("%i %s %s %s %i %i\n", al.Position, al.QueryBases.c_str(), get_cigar(al.CigarData).c_str(), al.Qualities.c_str(), al.MapQuality, al.IsReverseStrand() ? 1 : 0);
    }

    reader.Close();
  } catch (exception& e) {
    cerr << e.what() << endl;
    return 1;
  }
  return 0;
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#if defined(WEBRTC_ANDROID)
#include "webrtc/base/ifaddrs-android.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

namespace {

struct netlinkrequest {
  nlmsghdr header;
  ifaddrmsg msg;
};

const int kMaxReadSize = 4096;

}  // namespace

namespace rtc {

int set_ifname(struct ifaddrs* ifaddr, int interface) {
  char buf[IFNAMSIZ] = {0};
  char* name = if_indextoname(interface, buf);
  if (name == NULL) {
    return -1;
  }
  ifaddr->ifa_name = new char[strlen(name) + 1];
  strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
  return 0;
}

int set_flags(struct ifaddrs* ifaddr) {
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd == -1) {
    return -1;
  }
  ifreq ifr;
  memset(&ifr, 0, sizeof(ifr));
  strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
  int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
  close(fd);
  if (rc == -1) {
    return -1;
  }
  ifaddr->ifa_flags = ifr.ifr_flags;
  return 0;
}

int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
                  size_t len) {
  if (msg->ifa_family == AF_INET) {
    sockaddr_in* sa = new sockaddr_in;
    sa->sin_family = AF_INET;
    memcpy(&sa->sin_addr, data, len);
    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
  } else if (msg->ifa_family == AF_INET6) {
    sockaddr_in6* sa = new sockaddr_in6;
    sa->sin6_family = AF_INET6;
    sa->sin6_scope_id = msg->ifa_index;
    memcpy(&sa->sin6_addr, data, len);
    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
  } else {
    return -1;
  }
  return 0;
}

int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
  char* prefix = NULL;
  if (family == AF_INET) {
    sockaddr_in* mask = new sockaddr_in;
    mask->sin_family = AF_INET;
    memset(&mask->sin_addr, 0, sizeof(in_addr));
    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
    if (prefixlen > 32) {
      prefixlen = 32;
    }
    prefix = reinterpret_cast<char*>(&mask->sin_addr);
  } else if (family == AF_INET6) {
    sockaddr_in6* mask = new sockaddr_in6;
    mask->sin6_family = AF_INET6;
    memset(&mask->sin6_addr, 0, sizeof(in6_addr));
    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
    if (prefixlen > 128) {
      prefixlen = 128;
    }
    prefix = reinterpret_cast<char*>(&mask->sin6_addr);
  } else {
    return -1;
  }
  for (int i = 0; i < (prefixlen / 8); i++) {
    *prefix++ = 0xFF;
  }
  char remainder = 0xff;
  remainder <<= (8 - prefixlen % 8);
  *prefix = remainder;
  return 0;
}

int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
                     size_t len) {
  if (set_ifname(ifaddr, msg->ifa_index) != 0) {
    return -1;
  }
  if (set_flags(ifaddr) != 0) {
    return -1;
  }
  if (set_addresses(ifaddr, msg, bytes, len) != 0) {
    return -1;
  }
  if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
    return -1;
  }
  return 0;
}

int getifaddrs(struct ifaddrs** result) {
  int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (fd < 0) {
    return -1;
  }

  netlinkrequest ifaddr_request;
  memset(&ifaddr_request, 0, sizeof(ifaddr_request));
  ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
  ifaddr_request.header.nlmsg_type = RTM_GETADDR;
  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));

  ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
  if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
    close(fd);
    return -1;
  }
  struct ifaddrs* start = NULL;
  struct ifaddrs* current = NULL;
  char buf[kMaxReadSize];
  ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
  while (amount_read > 0) {
    nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
    size_t header_size = static_cast<size_t>(amount_read);
    for ( ; NLMSG_OK(header, header_size);
          header = NLMSG_NEXT(header, header_size)) {
      switch (header->nlmsg_type) {
        case NLMSG_DONE:
          // Success. Return.
          *result = start;
          close(fd);
          return 0;
        case NLMSG_ERROR:
          close(fd);
          freeifaddrs(start);
          return -1;
        case RTM_NEWADDR: {
          ifaddrmsg* address_msg =
              reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
          rtattr* rta = IFA_RTA(address_msg);
          ssize_t payload_len = IFA_PAYLOAD(header);
          while (RTA_OK(rta, payload_len)) {
            if (rta->rta_type == IFA_ADDRESS) {
              int family = address_msg->ifa_family;
              if (family == AF_INET || family == AF_INET6) {
                ifaddrs* newest = new ifaddrs;
                memset(newest, 0, sizeof(ifaddrs));
                if (current) {
                  current->ifa_next = newest;
                } else {
                  start = newest;
                }
                if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
                                     RTA_PAYLOAD(rta)) != 0) {
                  freeifaddrs(start);
                  *result = NULL;
                  return -1;
                }
                current = newest;
              }
            }
            rta = RTA_NEXT(rta, payload_len);
          }
          break;
        }
      }
    }
    amount_read = recv(fd, &buf, kMaxReadSize, 0);
  }
  close(fd);
  freeifaddrs(start);
  return -1;
}

void freeifaddrs(struct ifaddrs* addrs) {
  struct ifaddrs* last = NULL;
  struct ifaddrs* cursor = addrs;
  while (cursor) {
    delete[] cursor->ifa_name;
    delete cursor->ifa_addr;
    delete cursor->ifa_netmask;
    last = cursor;
    cursor = cursor->ifa_next;
    delete last;
  }
}
#endif  // defined(WEBRTC_ANDROID)

}  // namespace rtc
<commit_msg>Move end of namespace inside #ifdef<commit_after>/*
 *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#if defined(WEBRTC_ANDROID)
#include "webrtc/base/ifaddrs-android.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

namespace {

struct netlinkrequest {
  nlmsghdr header;
  ifaddrmsg msg;
};

const int kMaxReadSize = 4096;

}  // namespace

namespace rtc {

int set_ifname(struct ifaddrs* ifaddr, int interface) {
  char buf[IFNAMSIZ] = {0};
  char* name = if_indextoname(interface, buf);
  if (name == NULL) {
    return -1;
  }
  ifaddr->ifa_name = new char[strlen(name) + 1];
  strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
  return 0;
}

int set_flags(struct ifaddrs* ifaddr) {
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd == -1) {
    return -1;
  }
  ifreq ifr;
  memset(&ifr, 0, sizeof(ifr));
  strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
  int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
  close(fd);
  if (rc == -1) {
    return -1;
  }
  ifaddr->ifa_flags = ifr.ifr_flags;
  return 0;
}

int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
                  size_t len) {
  if (msg->ifa_family == AF_INET) {
    sockaddr_in* sa = new sockaddr_in;
    sa->sin_family = AF_INET;
    memcpy(&sa->sin_addr, data, len);
    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
  } else if (msg->ifa_family == AF_INET6) {
    sockaddr_in6* sa = new sockaddr_in6;
    sa->sin6_family = AF_INET6;
    sa->sin6_scope_id = msg->ifa_index;
    memcpy(&sa->sin6_addr, data, len);
    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
  } else {
    return -1;
  }
  return 0;
}

int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
  char* prefix = NULL;
  if (family == AF_INET) {
    sockaddr_in* mask = new sockaddr_in;
    mask->sin_family = AF_INET;
    memset(&mask->sin_addr, 0, sizeof(in_addr));
    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
    if (prefixlen > 32) {
      prefixlen = 32;
    }
    prefix = reinterpret_cast<char*>(&mask->sin_addr);
  } else if (family == AF_INET6) {
    sockaddr_in6* mask = new sockaddr_in6;
    mask->sin6_family = AF_INET6;
    memset(&mask->sin6_addr, 0, sizeof(in6_addr));
    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
    if (prefixlen > 128) {
      prefixlen = 128;
    }
    prefix = reinterpret_cast<char*>(&mask->sin6_addr);
  } else {
    return -1;
  }
  for (int i = 0; i < (prefixlen / 8); i++) {
    *prefix++ = 0xFF;
  }
  char remainder = 0xff;
  remainder <<= (8 - prefixlen % 8);
  *prefix = remainder;
  return 0;
}

int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
                     size_t len) {
  if (set_ifname(ifaddr, msg->ifa_index) != 0) {
    return -1;
  }
  if (set_flags(ifaddr) != 0) {
    return -1;
  }
  if (set_addresses(ifaddr, msg, bytes, len) != 0) {
    return -1;
  }
  if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
    return -1;
  }
  return 0;
}

int getifaddrs(struct ifaddrs** result) {
  int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (fd < 0) {
    return -1;
  }

  netlinkrequest ifaddr_request;
  memset(&ifaddr_request, 0, sizeof(ifaddr_request));
  ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
  ifaddr_request.header.nlmsg_type = RTM_GETADDR;
  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));

  ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
  if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
    close(fd);
    return -1;
  }
  struct ifaddrs* start = NULL;
  struct ifaddrs* current = NULL;
  char buf[kMaxReadSize];
  ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
  while (amount_read > 0) {
    nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
    size_t header_size = static_cast<size_t>(amount_read);
    for ( ; NLMSG_OK(header, header_size);
          header = NLMSG_NEXT(header, header_size)) {
      switch (header->nlmsg_type) {
        case NLMSG_DONE:
          // Success. Return.
          *result = start;
          close(fd);
          return 0;
        case NLMSG_ERROR:
          close(fd);
          freeifaddrs(start);
          return -1;
        case RTM_NEWADDR: {
          ifaddrmsg* address_msg =
              reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
          rtattr* rta = IFA_RTA(address_msg);
          ssize_t payload_len = IFA_PAYLOAD(header);
          while (RTA_OK(rta, payload_len)) {
            if (rta->rta_type == IFA_ADDRESS) {
              int family = address_msg->ifa_family;
              if (family == AF_INET || family == AF_INET6) {
                ifaddrs* newest = new ifaddrs;
                memset(newest, 0, sizeof(ifaddrs));
                if (current) {
                  current->ifa_next = newest;
                } else {
                  start = newest;
                }
                if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
                                     RTA_PAYLOAD(rta)) != 0) {
                  freeifaddrs(start);
                  *result = NULL;
                  return -1;
                }
                current = newest;
              }
            }
            rta = RTA_NEXT(rta, payload_len);
          }
          break;
        }
      }
    }
    amount_read = recv(fd, &buf, kMaxReadSize, 0);
  }
  close(fd);
  freeifaddrs(start);
  return -1;
}

void freeifaddrs(struct ifaddrs* addrs) {
  struct ifaddrs* last = NULL;
  struct ifaddrs* cursor = addrs;
  while (cursor) {
    delete[] cursor->ifa_name;
    delete cursor->ifa_addr;
    delete cursor->ifa_netmask;
    last = cursor;
    cursor = cursor->ifa_next;
    delete last;
  }
}

}  // namespace rtc
#endif  // defined(WEBRTC_ANDROID)
<|endoftext|>


<commit_before>#include <stdio.h>
#include "SqBiTree.h"

Status visit(TElemType e){
	printf("%c ",e);
	return OK;
}

int main(){
	SqBiTree bt;
	InitBiTree(bt);
	CreateBiTree(bt);
	PreOrderTraverse(bt,visit);
	InOrderTraverse(bt,visit);
	PostOrderTraverse(bt,visit);
	LevelOrderTraverse(bt,visit);
	PrintTree(bt);
	system("pause");
	return 0;
}

<commit_msg>Update Main.cpp<commit_after>#include <stdio.h>
#include "SqBiTree.h"

Status visit(TElemType e){
	printf("%c ",e);
	return OK;
}

int main(){
	SqBiTree bt;
	InitBiTree(bt);
	CreateBiTree(bt);
	PreOrderTraverse(bt,visit);
	InOrderTraverse(bt,visit);
	PostOrderTraverse(bt,visit);
	LevelOrderTraverse(bt,visit);
	PrintTree(bt);
	system("pause");
	return 0;
}

<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
    @brief  RX DSP サンプル @n
			RX64M, RX71M: @n
					12MHz のベースクロックを使用する @n
			　　　　P07 ピンにLEDを接続する @n
					SCI1 を使用する @n
			RX65N (Renesas Envision kit RX65N): @n
					12MHz のベースクロックを使用する @n
			　　　　P70 に接続された LED を利用する @n
					SCI9 を使用する @n
			RX24T: @n
					10MHz のベースクロックを使用する @n
			　　　　P00 ピンにLEDを接続する @n
					SCI1 を使用する @n
			RX66T: @n
					10MHz のベースクロックを使用する @n
			　　　　P00 ピンにLEDを接続する @n
					SCI1 を使用する @n
			RX72N: (Renesas Envision kit RX72N) @n
					16MHz のベースクロックを使用する @n
					P40 ピンにLEDを接続する @n
					SCI2 を使用する @n
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"

#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/cmt_mgr.hpp"
#include "common/command.hpp"

#include "common/format.hpp"
#include "common/input.hpp"

namespace {

#if defined(SIG_RX71M)
	static const char* system_str_ = { "RX71M" };
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX64M)
	static const char* system_str_ = { "RX64M" };
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX65N)
	static const char* system_str_ = { "RX65N" };
	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
	typedef device::SCI9 SCI_CH;
#elif defined(SIG_RX24T)
	static const char* system_str_ = { "RX24T" };
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX66T)
	static const char* system_str_ = { "RX66T" };
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX72N)
	static const char* system_str_ = { "RX72N" };
	typedef device::PORT<device::PORT4, device::bitpos::B0> LED;
	typedef device::SCI2 SCI_CH;
#elif defined(SIG_RX72T)
	static const char* system_str_ = { "RX72T" };
	typedef device::PORT<device::PORT0, device::bitpos::B1> LED;
	typedef device::SCI1 SCI_CH;
#endif
// クロックの定義は、「RXxxx/clock_profile.hpp」を参照。
	typedef device::system_io<> SYSTEM_IO;
// 内蔵高速発信器
//	typedef device::system_io<device::system_base::OSC_TYPE::HOCO> SYSTEM_IO;

	typedef utils::fixed_fifo<char, 512> RXB;  // RX (受信) バッファの定義
	typedef utils::fixed_fifo<char, 256> TXB;  // TX (送信) バッファの定義

	typedef device::sci_io<SCI_CH, RXB, TXB> SCI;
// SCI ポートの第二候補を選択する場合
//	typedef device::sci_io<SCI_CH, RXB, TXB, device::port_map::ORDER::SECOND> SCI;
	SCI		sci_;

	typedef device::cmt_mgr<device::CMT0> CMT;
	CMT		cmt_;

	const uint32_t PARAM_SIZE = 1024;
	int32_t	parama_[PARAM_SIZE];
	int32_t	paramb_[PARAM_SIZE];

	int32_t dsp_opr_(uint32_t loop)
	{
#ifdef __RXV3__
		__mvtacgu_a0(0);
#endif
		__mvtachi_a0(0);
		__mvtaclo_a0(0);
		for(uint32_t i = 0; i < loop; ++i) {
			auto a = parama_[i % PARAM_SIZE];
			auto b = paramb_[i % PARAM_SIZE];
			__emaca_a0(a, b);
		}
		return __mvfaclo_s0_a0();
	}

	int32_t cpu_opr_(uint32_t loop)
	{
		int32_t sum = 0;
		for(uint32_t i = 0; i < loop; ++i) {
			auto a = parama_[i % PARAM_SIZE];
			auto b = paramb_[i % PARAM_SIZE];
			sum += a * b;
		}
		return sum;
	}
}

extern "C" {

	// syscalls.c から呼ばれる、標準出力（stdout, stderr）
	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	// syscalls.c から呼ばれる、標準入力（stdin）
	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}
}

int main(int argc, char** argv);

int main(int argc, char** argv)
{
	SYSTEM_IO::boost_master_clock();

	{  // タイマー設定（1000Hz）
		uint8_t intr = 4;
		cmt_.start(1000, intr);
	}

	{  // SCI の開始
		uint8_t intr = 2;        // 割り込みレベル（０を指定すると、ポーリング動作になる）
		uint32_t baud = 115200;  // ボーレート（任意の整数値を指定可能）
		sci_.start(baud, intr);  // 標準では、８ビット、１ストップビットを選択
	}

	auto clk = device::clock_profile::ICLK / 1'000'000;
	utils::format("Start DSP sample for '%s' %d[MHz]\n") % system_str_ % clk;

	LED::DIR = 1;
	LED::P = 0;

	{
		utils::format("SCI PCLK: %u\n") % SCI_CH::PCLK;
		utils::format("SCI Baud rate (set):  %u\n") % sci_.get_baud_rate();
		float rate = 1.0f - static_cast<float>(sci_.get_baud_rate()) / sci_.get_baud_rate(true);
		rate *= 100.0f;
		utils::format("SCI Baud rate (real): %u (%3.2f [%%])\n") % sci_.get_baud_rate(true) % rate;
		utils::format("CMT rate (set):  %d [Hz]\n") % cmt_.get_rate();
		rate = 1.0f - static_cast<float>(cmt_.get_rate()) / cmt_.get_rate(true);
		rate *= 100.0f;
		utils::format("CMT rate (real): %d [Hz] (%3.2f [%%])\n") % cmt_.get_rate(true) % rate;
	}

	cmt_.sync();

	for(uint32_t i = 0; i < PARAM_SIZE; ++i) {
		parama_[i] = rand() & 0x8fffffff;
		paramb_[i] = rand() & 0x8fffffff;
	}

	uint32_t loop = 50000000;
	{
		auto st = cmt_.get_counter();
		auto a = dsp_opr_(loop);
		auto et = cmt_.get_counter();
		utils::format("DSP %d loops: ans = %d, (%u [ms])\n") % loop % a % (et - st);
	}

	{
		auto st = cmt_.get_counter();
		auto a = cpu_opr_(loop);
		auto et = cmt_.get_counter();
		utils::format("CPU %d loops: ans = %d, (%u [ms])\n") % loop % a % (et - st);
	}

	uint16_t cnt = 0;
	while(1) {
		cmt_.sync();

		++cnt;
		if(cnt >= (50 * 10)) {
			cnt = 0;
		}
		if(cnt < (25 * 10)) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<commit_msg>Update: cleanup<commit_after>//=====================================================================//
/*! @file
    @brief  RX DSP サンプル @n
			RX64M, RX71M: @n
					12MHz のベースクロックを使用する @n
			　　　　P07 ピンにLEDを接続する @n
					SCI1 を使用する @n
			RX65N (Renesas Envision kit RX65N): @n
					12MHz のベースクロックを使用する @n
			　　　　P70 に接続された LED を利用する @n
					SCI9 を使用する @n
			RX24T: @n
					10MHz のベースクロックを使用する @n
			　　　　P00 ピンにLEDを接続する @n
					SCI1 を使用する @n
			RX66T: @n
					10MHz のベースクロックを使用する @n
			　　　　P00 ピンにLEDを接続する @n
					SCI1 を使用する @n
			RX72N: (Renesas Envision kit RX72N) @n
					16MHz のベースクロックを使用する @n
					P40 ピンにLEDを接続する @n
					SCI2 を使用する @n
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"

#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/cmt_mgr.hpp"
#include "common/command.hpp"

#include "common/format.hpp"
#include "common/input.hpp"

namespace {

#if defined(SIG_RX71M)
	static const char* system_str_ = { "RX71M" };
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX64M)
	static const char* system_str_ = { "RX64M" };
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX65N)
	static const char* system_str_ = { "RX65N" };
	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
	typedef device::SCI9 SCI_CH;
#elif defined(SIG_RX24T)
	static const char* system_str_ = { "RX24T" };
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX66T)
	static const char* system_str_ = { "RX66T" };
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX72N)
	static const char* system_str_ = { "RX72N" };
	typedef device::PORT<device::PORT4, device::bitpos::B0> LED;
	typedef device::SCI2 SCI_CH;
#elif defined(SIG_RX72T)
	static const char* system_str_ = { "RX72T" };
	typedef device::PORT<device::PORT0, device::bitpos::B1> LED;
	typedef device::SCI1 SCI_CH;
#endif
// クロックの定義は、「RXxxx/clock_profile.hpp」を参照。
	typedef device::system_io<> SYSTEM_IO;

	typedef utils::fixed_fifo<char, 512> RXB;  // RX (受信) バッファの定義
	typedef utils::fixed_fifo<char, 256> TXB;  // TX (送信) バッファの定義

	typedef device::sci_io<SCI_CH, RXB, TXB> SCI;
// SCI ポートの第二候補を選択する場合
//	typedef device::sci_io<SCI_CH, RXB, TXB, device::port_map::ORDER::SECOND> SCI;
	SCI		sci_;

	typedef device::cmt_mgr<device::CMT0> CMT;
	CMT		cmt_;

	const uint32_t PARAM_SIZE = 1024;
	int32_t	parama_[PARAM_SIZE];
	int32_t	paramb_[PARAM_SIZE];

	int32_t dsp_opr_(uint32_t loop)
	{
#ifdef __RXV3__
		__mvtacgu_a0(0);
#endif
		__mvtachi_a0(0);
		__mvtaclo_a0(0);
		for(uint32_t i = 0; i < loop; ++i) {
			auto a = parama_[i % PARAM_SIZE];
			auto b = paramb_[i % PARAM_SIZE];
			__emaca_a0(a, b);
		}
		return __mvfaclo_s0_a0();
	}

	int32_t cpu_opr_(uint32_t loop)
	{
		int32_t sum = 0;
		for(uint32_t i = 0; i < loop; ++i) {
			auto a = parama_[i % PARAM_SIZE];
			auto b = paramb_[i % PARAM_SIZE];
			sum += a * b;
		}
		return sum;
	}
}

extern "C" {

	// syscalls.c から呼ばれる、標準出力（stdout, stderr）
	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	// syscalls.c から呼ばれる、標準入力（stdin）
	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}
}

int main(int argc, char** argv);

int main(int argc, char** argv)
{
	SYSTEM_IO::boost_master_clock();

	{  // タイマー設定（1000Hz）
		uint8_t intr = 4;
		cmt_.start(1000, intr);
	}

	{  // SCI の開始
		uint8_t intr = 2;        // 割り込みレベル（０を指定すると、ポーリング動作になる）
		uint32_t baud = 115200;  // ボーレート（任意の整数値を指定可能）
		sci_.start(baud, intr);  // 標準では、８ビット、１ストップビットを選択
	}

	auto clk = device::clock_profile::ICLK / 1'000'000;
	utils::format("Start DSP sample for '%s' %d[MHz]\n") % system_str_ % clk;

	LED::DIR = 1;
	LED::P = 0;

	{
		utils::format("SCI PCLK: %u\n") % SCI_CH::PCLK;
		utils::format("SCI Baud rate (set):  %u\n") % sci_.get_baud_rate();
		float rate = 1.0f - static_cast<float>(sci_.get_baud_rate()) / sci_.get_baud_rate(true);
		rate *= 100.0f;
		utils::format("SCI Baud rate (real): %u (%3.2f [%%])\n") % sci_.get_baud_rate(true) % rate;
		utils::format("CMT rate (set):  %d [Hz]\n") % cmt_.get_rate();
		rate = 1.0f - static_cast<float>(cmt_.get_rate()) / cmt_.get_rate(true);
		rate *= 100.0f;
		utils::format("CMT rate (real): %d [Hz] (%3.2f [%%])\n") % cmt_.get_rate(true) % rate;
	}

	cmt_.sync();

	for(uint32_t i = 0; i < PARAM_SIZE; ++i) {
		parama_[i] = rand() & 0x8fffffff;
		paramb_[i] = rand() & 0x8fffffff;
	}

	uint32_t loop = 50000000;
	{
		auto st = cmt_.get_counter();
		auto a = dsp_opr_(loop);
		auto et = cmt_.get_counter();
		utils::format("DSP %d loops: ans = %d, (%u [ms])\n") % loop % a % (et - st);
	}

	{
		auto st = cmt_.get_counter();
		auto a = cpu_opr_(loop);
		auto et = cmt_.get_counter();
		utils::format("CPU %d loops: ans = %d, (%u [ms])\n") % loop % a % (et - st);
	}

	uint16_t cnt = 0;
	while(1) {
		cmt_.sync();

		++cnt;
		if(cnt >= (50 * 10)) {
			cnt = 0;
		}
		if(cnt < (25 * 10)) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<|endoftext|>


<commit_before>#include "wled.h"

/*
 * Physical IO
 */

#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)

void shortPressAction(uint8_t b)
{
  if (!macroButton[b])
  {
    toggleOnOff();
    colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
  } else {
    applyPreset(macroButton[b]);
  }
}

bool isButtonPressed(uint8_t i)
{
  if (btnPin[i]<0) return false;
  switch (buttonType[i]) {
    case BTN_TYPE_NONE:
    case BTN_TYPE_RESERVED:
      break;
    case BTN_TYPE_PUSH:
    case BTN_TYPE_SWITCH:
      if (digitalRead(btnPin[i]) == LOW) return true;
      break;
    case BTN_TYPE_PUSH_ACT_HIGH:
    case BTN_TYPE_SWITCH_ACT_HIGH:
      if (digitalRead(btnPin[i]) == HIGH) return true;
      break;
    case BTN_TYPE_TOUCH:
      #ifdef ARDUINO_ARCH_ESP32
      if (touchRead(btnPin[i]) <= touchThreshold) return true;
      #endif
      break;
  }
  return false;
}

void handleSwitch(uint8_t b)
{
  if (buttonPressedBefore[b] != isButtonPressed(b)) {
    buttonPressedTime[b] = millis();
    buttonPressedBefore[b] = !buttonPressedBefore[b];
  }

  if (buttonLongPressed[b] == buttonPressedBefore[b]) return;

  if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
    if (buttonPressedBefore[b]) { //LOW, falling edge, switch closed
      if (macroButton[b]) applyPreset(macroButton[b]);
      else { //turn on
        if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
      }
    } else { //HIGH, rising edge, switch opened
      if (macroLongPress[b]) applyPreset(macroLongPress[b]);
      else { //turn off
        if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
      }
    }
    buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state
  }
}

void handleAnalog(uint8_t b)
{
  static uint8_t oldRead[WLED_MAX_BUTTONS];
  #ifdef ESP8266
  uint8_t aRead = analogRead(A0) >> 2; // convert 10bit read to 8bit
  #else
  uint8_t aRead = analogRead(btnPin[b]) >> 4; // convert 12bit read to 8bit
  #endif

  if (oldRead[b] == aRead) return;  // no change in reading

  // if no macro for "short press" and "long press" is defined use brightness control
  if (!macroButton[b] && !macroLongPress[b]) {
    // if "double press" macro is 250 or greater use global brightness
    if (macroDoublePress[b]>=250) {
      // if change in analog read was detected change global brightness
      bri = aRead;
    } else {
      // otherwise use "double press" for segment selection
      //uint8_t mainSeg = strip.getMainSegmentId();
      WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]);
      if (aRead == 0) {
        seg.setOption(SEG_OPTION_ON, 0, macroDoublePress[b]); // off
      } else {
        seg.setOpacity(aRead, macroDoublePress[b]);
        seg.setOption(SEG_OPTION_ON, 1, macroDoublePress[b]);
      }
    }
  } else {
    //TODO:
    // we can either trigger a preset depending on the level (between short and long entries)
    // or use it for RGBW direct control
  }
  colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
}

void handleButton()
{
  for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
    if (btnPin[b]<0 || !(buttonType[b] > BTN_TYPE_NONE)) continue;

    if (buttonType[b] == BTN_TYPE_ANALOG) {   // button is not a button but a potentiometer
      handleAnalog(b); continue;
    }

    if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_SWITCH_ACT_HIGH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
      handleSwitch(b); continue;
    }

    //momentary button logic
    if (isButtonPressed(b)) //pressed
    {
      if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
      buttonPressedBefore[b] = true;

      if (millis() - buttonPressedTime[b] > 600) //long press
      {
        if (!buttonLongPressed[b])
        {
          if (macroLongPress[b]) {applyPreset(macroLongPress[b]);}
          else _setRandomColor(false,true);

          buttonLongPressed[b] = true;
        }
      }
    }
    else if (!isButtonPressed(b) && buttonPressedBefore[b]) //released
    {
      long dur = millis() - buttonPressedTime[b];
      if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
      bool doublePress = buttonWaitTime[b];
      buttonWaitTime[b] = 0;

      if (dur > 6000 && b==0) //long press on button 0
      {
        WLED::instance().initAP(true);
      }
      else if (!buttonLongPressed[b]) { //short press
        if (macroDoublePress[b])
        {
          if (doublePress) applyPreset(macroDoublePress[b]);
          else buttonWaitTime[b] = millis();
        } else shortPressAction(b);
      }
      buttonPressedBefore[b] = false;
      buttonLongPressed[b] = false;
    }

    if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 450 && !buttonPressedBefore[b])
    {
      buttonWaitTime[b] = 0;
      shortPressAction(b);
    }
  }
}

void handleIO()
{
  handleButton();

  //set relay when LEDs turn on
  if (strip.getBrightness())
  {
    lastOnTime = millis();
    if (offMode)
    {
      if (rlyPin>=0) {
        pinMode(rlyPin, OUTPUT);
        digitalWrite(rlyPin, rlyMde);
      }
      offMode = false;
    }
  } else if (millis() - lastOnTime > 600)
  {
    if (!offMode) {
      #ifdef ESP8266
      // turn off built-in LED if strip is turned off
      // this will break digital bus so will need to be reinitialised on On
      pinMode(LED_BUILTIN, OUTPUT);
      digitalWrite(LED_BUILTIN, HIGH);
      #endif
      if (rlyPin>=0) {
        pinMode(rlyPin, OUTPUT);
        digitalWrite(rlyPin, !rlyMde);
      }
    }
    offMode = true;
  }
}
<commit_msg>Fixes for analog.<commit_after>#include "wled.h"

/*
 * Physical IO
 */

#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)

void shortPressAction(uint8_t b)
{
  if (!macroButton[b])
  {
    toggleOnOff();
    colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
  } else {
    applyPreset(macroButton[b]);
  }
}

bool isButtonPressed(uint8_t i)
{
  if (btnPin[i]<0) return false;
  switch (buttonType[i]) {
    case BTN_TYPE_NONE:
    case BTN_TYPE_RESERVED:
      break;
    case BTN_TYPE_PUSH:
    case BTN_TYPE_SWITCH:
      if (digitalRead(btnPin[i]) == LOW) return true;
      break;
    case BTN_TYPE_PUSH_ACT_HIGH:
    case BTN_TYPE_SWITCH_ACT_HIGH:
      if (digitalRead(btnPin[i]) == HIGH) return true;
      break;
    case BTN_TYPE_TOUCH:
      #ifdef ARDUINO_ARCH_ESP32
      if (touchRead(btnPin[i]) <= touchThreshold) return true;
      #endif
      break;
  }
  return false;
}

void handleSwitch(uint8_t b)
{
  if (buttonPressedBefore[b] != isButtonPressed(b)) {
    buttonPressedTime[b] = millis();
    buttonPressedBefore[b] = !buttonPressedBefore[b];
  }

  if (buttonLongPressed[b] == buttonPressedBefore[b]) return;

  if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
    if (buttonPressedBefore[b]) { //LOW, falling edge, switch closed
      if (macroButton[b]) applyPreset(macroButton[b]);
      else { //turn on
        if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
      }
    } else { //HIGH, rising edge, switch opened
      if (macroLongPress[b]) applyPreset(macroLongPress[b]);
      else { //turn off
        if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
      }
    }
    buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state
  }
}

void handleAnalog(uint8_t b)
{
  static uint8_t oldRead[WLED_MAX_BUTTONS];
  #ifdef ESP8266
  uint16_t aRead = analogRead(A0) >> 5; // convert 10bit read to 5bit (remove noise)
  #else
  uint16_t aRead = analogRead(btnPin[b]) >> 7; // convert 12bit read to 5bit (remove noise)
  #endif

  if (oldRead[b] == aRead) return;  // no change in reading
  oldRead[b] = aRead;

  // if no macro for "short press" and "long press" is defined use brightness control
  if (!macroButton[b] && !macroLongPress[b]) {
    // if "double press" macro is 250 or greater use global brightness
    if (macroDoublePress[b] >= 250) {
      // if change in analog read was detected change global brightness
      if (aRead == 0) {
        briLast = bri;
        bri = 0;
      } else{
        bri = aRead << 3;
      }
    } else {
      // otherwise use "double press" for segment selection
      //uint8_t mainSeg = strip.getMainSegmentId();
      WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]);
      if (aRead == 0) {
        seg.setOption(SEG_OPTION_ON, 0); // off
      } else {
        seg.setOpacity(aRead << 3, macroDoublePress[b]);
        seg.setOption(SEG_OPTION_ON, 1);
      }
      // this will notify clients of update (websockets,mqtt,etc)
      //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
      // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
      updateInterfaces(NOTIFIER_CALL_MODE_BUTTON);
    }
  } else {
    //TODO:
    // we can either trigger a preset depending on the level (between short and long entries)
    // or use it for RGBW direct control
  }
  //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
  // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
  colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
}

void handleButton()
{
  static unsigned long lastRead = 0UL;

  for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
    if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue;

    if (buttonType[b] == BTN_TYPE_ANALOG && millis() - lastRead > 250) {   // button is not a button but a potentiometer
      if (b+1 == WLED_MAX_BUTTONS) lastRead = millis();
      handleAnalog(b); continue;
    }

    if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_SWITCH_ACT_HIGH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
      handleSwitch(b); continue;
    }

    //momentary button logic
    if (isButtonPressed(b)) //pressed
    {
      if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
      buttonPressedBefore[b] = true;

      if (millis() - buttonPressedTime[b] > 600) //long press
      {
        if (!buttonLongPressed[b])
        {
          if (macroLongPress[b]) {applyPreset(macroLongPress[b]);}
          else _setRandomColor(false,true);

          buttonLongPressed[b] = true;
        }
      }
    }
    else if (!isButtonPressed(b) && buttonPressedBefore[b]) //released
    {
      long dur = millis() - buttonPressedTime[b];
      if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
      bool doublePress = buttonWaitTime[b];
      buttonWaitTime[b] = 0;

      if (dur > 6000 && b==0) //long press on button 0
      {
        WLED::instance().initAP(true);
      }
      else if (!buttonLongPressed[b]) { //short press
        if (macroDoublePress[b])
        {
          if (doublePress) applyPreset(macroDoublePress[b]);
          else buttonWaitTime[b] = millis();
        } else shortPressAction(b);
      }
      buttonPressedBefore[b] = false;
      buttonLongPressed[b] = false;
    }

    if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 450 && !buttonPressedBefore[b])
    {
      buttonWaitTime[b] = 0;
      shortPressAction(b);
    }
  }
}

void handleIO()
{
  handleButton();

  //set relay when LEDs turn on
  if (strip.getBrightness())
  {
    lastOnTime = millis();
    if (offMode)
    {
      if (rlyPin>=0) {
        pinMode(rlyPin, OUTPUT);
        digitalWrite(rlyPin, rlyMde);
      }
      offMode = false;
    }
  } else if (millis() - lastOnTime > 600)
  {
    if (!offMode) {
      #ifdef ESP8266
      // turn off built-in LED if strip is turned off
      // this will break digital bus so will need to be reinitialised on On
      pinMode(LED_BUILTIN, OUTPUT);
      digitalWrite(LED_BUILTIN, HIGH);
      #endif
      if (rlyPin>=0) {
        pinMode(rlyPin, OUTPUT);
        digitalWrite(rlyPin, !rlyMde);
      }
    }
    offMode = true;
  }
}
<|endoftext|>