<commit_before>/* tests/test-sparse2.C
 * Copyright (C) 2014 the LinBox group
 *
 * Written by bds <saunders@udel.edu>
 *            BB <bbboyer@ncsu.edu>
 *
 * --------------------------------------------------------
 *
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *
 */

/*! @file  tests/test-sparse.C
 * @ingroup tests
 *
 * @brief no doc
 *
 * @test no doc.
 */

#include "linbox/linbox-config.h"

#include <iostream>
#include <fstream>
#include <sstream>

#include "linbox/util/commentator.h"
#include "linbox/field/modular.h"
#include "linbox/matrix/sparse.h"
#include "linbox/matrix/sparse-matrix.h"

#include "test-blackbox.h"

using namespace LinBox;

template <class SM>
void buildBySetEntry(SM & A, size_t nnz)
{
	typename SM::Field::RandIter r(A.field(),0);
	//size_t i, j, k;
	typename SM::Field::Element x;

	for (size_t k = 0; k < nnz; ++k)
	{
		size_t i = random() % A.rowdim();
		size_t j = random() % A.coldim();
		r.nonzerorandom(x);
		// r.random(x); // I want to see what happens when one reads in zero. If we don't want it, we just stop permitting setting zero... (hence the clearEntry function)
		// std::cout << "A[ " << i+1 << ',' << j+1 << "]:=" << x << ';' << std::endl;
		// if (A.field().isZero(x)) std::cout << "#is zero" << std::endl;
		A.setEntry(i,j,x);
	}
	A.finalize();
	// std::cout << "B :=" << std::endl;
	// A.write(std::cout);
	// std::cout << ';' << std::endl;
}

int main (int argc, char **argv)
{
	bool pass = true;

	static size_t n = 10;
	static size_t m = 10;
	static integer q = 11;
	static size_t N = m+n;

	static Argument args[] = {
		{ 'n', "-n N", "Set column dimension of test matrices to N.", TYPE_INT,     &n },
		{ 'm', "-m M", "Set row dimension of test matrices to M.", TYPE_INT,     &m },
		{ 'q', "-q Q", "Operate over the \"field\" GF(Q) [1].", TYPE_INTEGER, &q },
		{ 'N', "-N N", "N nonzero Elements in sparse matrices.", TYPE_INT,     &N },
		END_OF_ARGUMENTS
	};
	parseArguments (argc, argv, args);

	//typedef	Modular<uint32_t> Field;
	typedef	Modular<double> Field;
	// typedef Field::Element  Element;

	Field F (q);

	commentator().getMessageClass (INTERNAL_DESCRIPTION).setMaxDepth (5);
	commentator().getMessageClass (INTERNAL_DESCRIPTION).setMaxDetailLevel (Commentator::LEVEL_UNIMPORTANT);

	commentator().start("Sparse matrix black box test suite", "Sparse");
	MatrixDomain<Field> MD(F) ;

	 /*  default */
	commentator().start("SparseMatrix<Field>", "Field");
	SparseMatrix<Field> S1(F, m, n);
	buildBySetEntry(S1, N);
	// it is assumed that any other matrix is built with the same random number generator  with the same seed
	if ( testBlackbox(S1,false))
		commentator().stop("SparseMatrix<Field> pass");
	else {
		commentator().stop("SparseMatrix<Field> FAIL");
		pass = false;
	}

	{ /*  COO */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::COO>", "COO");
		SparseMatrix<Field, SparseMatrixFormat::COO> S2(F, m, n);
		buildBySetEntry(S2, N);
		if ( testBlackbox(S2,false)  && MD.areEqual(S1,S2) )
			commentator().stop("Format COO pass");
		else {
			commentator().stop("Format COO FAIL");
			pass = false;
		}
	}

	{ /*  CSR  */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::CSR>", "CSR");
		SparseMatrix<Field, SparseMatrixFormat::CSR> S3(F, m, n);
		buildBySetEntry(S3, N);
		if ( testBlackbox(S3,false)  && MD.areEqual(S1,S3))
			commentator().stop("Format CSR pass");
		else {
			commentator().stop("Format CSR FAIL");
			pass = false;
		}
	}

	{ /*  ELL  */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::ELL>", "ELL");
		commentator().report() << "SparseMatrix<Field, SparseMatrixFormat::ELL>" << std::endl;
		SparseMatrix<Field, SparseMatrixFormat::ELL> S4(F, m, n);
		buildBySetEntry(S4, N);
		if ( testBlackbox(S4,false)  && MD.areEqual(S1,S4))
			commentator().stop("Format ELL pass");
		else {
			commentator().stop("Format ELL FAIL");
			pass = false;
		}
	}

	{ /*  ELL_R  */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::ELL_R>", "ELL_R");
		SparseMatrix<Field, SparseMatrixFormat::ELL_R> S5(F, m, n);
		buildBySetEntry(S5, N);
		if ( testBlackbox(S5,false)  && MD.areEqual(S1,S5))
			commentator().stop("Format ELL_R pass");
		else {
			commentator().stop("Format ELL_R FAIL");
			pass = false;
		}
	}

#if 0 // doesn't compile
	commentator().start("SparseMatrix<Field, SparseMatrixFormat::HYB>", "HYB");
	SparseMatrix<Field, SparseMatrixFormat::HYB> S6(F, m, n);
	buildBySetEntry(S6, N);
	S6.optimise();
	if ( testBlackbox(S6,false)  && MD.areEqual(S1,S6))
		commentator().stop("Format HYB pass");
	else {
		commentator().stop("Format HYB FAIL");
		pass = false;
	}
#endif

	{ /* SparseSeq: Vector of row, row is Vector of index/value Pair */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::SparseSeq>", "VVP");
		SparseMatrix<Field, SparseMatrixFormat::SparseSeq> S7(F, m, n);
		buildBySetEntry(S7, N);
		if ( testBlackbox(S7,true)  && MD.areEqual(S1,S7))
			commentator().stop("Format VVP pass");
		else {
			commentator().stop("Format VVP FAIL");
			pass = false;
		}
	}

	{ /*  SparsePar */
		// Vector of row, row is Pair of Vectors, one of indices, one of values.
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::SparsePar>", "VPV");
		SparseMatrix<Field, SparseMatrixFormat::SparsePar> S8(F, m, n);
		buildBySetEntry(S8, N);
		if ( testBlackbox(S8,true)  && MD.areEqual(S1,S8))
			commentator().stop("Format VPV pass");
		else {
			commentator().stop("Format VPV FAIL");
			pass = false;
		}
	}

	{ /*  SparseMap */
		// Vector of row, row is Map, index to value.
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::SparseMap>", "VMap");
		SparseMatrix<Field, SparseMatrixFormat::SparseMap> S9(F, m, n);
		buildBySetEntry(S9, N);
		if ( testBlackbox(S9,true)  && MD.areEqual(S1,S9))
			commentator().stop("Format VMap pass");
		else {
			commentator().stop("Format VMap FAIL");
			pass = false;
		}
	}

	{ /* TPL: Vector of i,j,val triples */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::TPL>", "TPL");
		SparseMatrix<Field, SparseMatrixFormat::TPL> S10(F, m, n);
		buildBySetEntry(S10, N);
		if ( testBlackbox(S10,true)  && MD.areEqual(S1,S10))
			commentator().stop("Format TPL pass");
		else {
			commentator().stop("Format TPL FAIL");
			pass = false;
		}

		}

	{ /*  Default OLD */
		commentator().start("SparseMatrix<Field>", "Field");
		Protected::SparseMatrixGeneric<Field> S11(F, m, n);
		buildBySetEntry(S11, N);
		if ( testBlackbox(S1,true)  && MD.areEqual(S1,S11))
			commentator().stop("SparseMatrix<Field> pass");
		else {
			commentator().stop("SparseMatrix<Field> FAIL");
			pass = false;
		}
	}

	if (pass)
		commentator().stop("Sparse matrix black box test suite pass");
	else
		commentator().stop("Sparse matrix black box test suite FAIL");

	return pass ? 0 : -1;
}

// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,:0,t0,+0,=s
// Local Variables:
// mode: C++
// tab-width: 8
// indent-tabs-mode: nil
// c-basic-offset: 8
// End:

<commit_msg>really seeded<commit_after>/* tests/test-sparse2.C
 * Copyright (C) 2014 the LinBox group
 *
 * Written by bds <saunders@udel.edu>
 *            BB <bbboyer@ncsu.edu>
 *
 * --------------------------------------------------------
 *
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *
 */

/*! @file  tests/test-sparse.C
 * @ingroup tests
 *
 * @brief no doc
 *
 * @test no doc.
 */

#include "linbox/linbox-config.h"

#include <iostream>
#include <fstream>
#include <sstream>

#include "linbox/util/commentator.h"
#include "linbox/field/modular.h"
#include "linbox/matrix/sparse.h"
#include "linbox/matrix/sparse-matrix.h"

#include "test-blackbox.h"

using namespace LinBox;

template <class SM>
void buildBySetEntry(SM & A, size_t nnz)
{
	typename SM::Field::RandIter r(A.field(),0);
	srand(0);

	//size_t i, j, k;
	typename SM::Field::Element x;

	for (size_t k = 0; k < nnz; ++k)
	{
		size_t i = rand() % A.rowdim();
		size_t j = rand() % A.coldim();
		r.nonzerorandom(x);
		// r.random(x); // I want to see what happens when one reads in zero. If we don't want it, we just stop permitting setting zero... (hence the clearEntry function)
		// std::cout << "A[ " << i+1 << ',' << j+1 << "]:=" << x << ';' << std::endl;
		// if (A.field().isZero(x)) std::cout << "#is zero" << std::endl;
		// std::cout << i << ',' << j << ',' << x << std::endl;
		A.setEntry(i,j,x);
	}
	// std::cout << "---" << std::endl;
	A.finalize();
	// std::cout << "B :=" << std::endl;
	// A.write(std::cout);
	// std::cout << ';' << std::endl;
}

int main (int argc, char **argv)
{
	bool pass = true;

	static size_t n = 10;
	static size_t m = 10;
	static integer q = 11;
	static size_t N = m+n;

	static Argument args[] = {
		{ 'n', "-n N", "Set column dimension of test matrices to N.", TYPE_INT,     &n },
		{ 'm', "-m M", "Set row dimension of test matrices to M.", TYPE_INT,     &m },
		{ 'q', "-q Q", "Operate over the \"field\" GF(Q) [1].", TYPE_INTEGER, &q },
		{ 'N', "-N N", "N nonzero Elements in sparse matrices.", TYPE_INT,     &N },
		END_OF_ARGUMENTS
	};
	parseArguments (argc, argv, args);

	//typedef	Modular<uint32_t> Field;
	typedef	Modular<double> Field;
	// typedef Field::Element  Element;

	Field F (q);

	commentator().getMessageClass (INTERNAL_DESCRIPTION).setMaxDepth (5);
	commentator().getMessageClass (INTERNAL_DESCRIPTION).setMaxDetailLevel (Commentator::LEVEL_UNIMPORTANT);

	commentator().start("Sparse matrix black box test suite", "Sparse");
	MatrixDomain<Field> MD(F) ;

	 /*  default */
	commentator().start("SparseMatrix<Field>", "Field");
	SparseMatrix<Field> S1(F, m, n);
	buildBySetEntry(S1, N);
	// it is assumed that any other matrix is built with the same random number generator  with the same seed
	if ( testBlackbox(S1,false))
		commentator().stop("SparseMatrix<Field> pass");
	else {
		commentator().stop("SparseMatrix<Field> FAIL");
		pass = false;
	}

	{ /*  COO */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::COO>", "COO");
		SparseMatrix<Field, SparseMatrixFormat::COO> S2(F, m, n);
		buildBySetEntry(S2, N);
		if ( testBlackbox(S2,false)  && MD.areEqual(S1,S2) )
			commentator().stop("Format COO pass");
		else {
			commentator().stop("Format COO FAIL");
			pass = false;
		}
	}

	{ /*  CSR  */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::CSR>", "CSR");
		SparseMatrix<Field, SparseMatrixFormat::CSR> S3(F, m, n);
		buildBySetEntry(S3, N);
		if ( testBlackbox(S3,false)  && MD.areEqual(S1,S3))
			commentator().stop("Format CSR pass");
		else {
			commentator().stop("Format CSR FAIL");
			pass = false;
		}
	}

	{ /*  ELL  */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::ELL>", "ELL");
		commentator().report() << "SparseMatrix<Field, SparseMatrixFormat::ELL>" << std::endl;
		SparseMatrix<Field, SparseMatrixFormat::ELL> S4(F, m, n);
		buildBySetEntry(S4, N);
		if ( testBlackbox(S4,false)  && MD.areEqual(S1,S4))
			commentator().stop("Format ELL pass");
		else {
			commentator().stop("Format ELL FAIL");
			pass = false;
		}
	}

	{ /*  ELL_R  */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::ELL_R>", "ELL_R");
		SparseMatrix<Field, SparseMatrixFormat::ELL_R> S5(F, m, n);
		buildBySetEntry(S5, N);
		if ( testBlackbox(S5,false)  && MD.areEqual(S1,S5))
			commentator().stop("Format ELL_R pass");
		else {
			commentator().stop("Format ELL_R FAIL");
			pass = false;
		}
	}

#if 0 // doesn't compile
	commentator().start("SparseMatrix<Field, SparseMatrixFormat::HYB>", "HYB");
	SparseMatrix<Field, SparseMatrixFormat::HYB> S6(F, m, n);
	buildBySetEntry(S6, N);
	S6.optimise();
	if ( testBlackbox(S6,false)  && MD.areEqual(S1,S6))
		commentator().stop("Format HYB pass");
	else {
		commentator().stop("Format HYB FAIL");
		pass = false;
	}
#endif

	{ /* SparseSeq: Vector of row, row is Vector of index/value Pair */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::SparseSeq>", "VVP");
		SparseMatrix<Field, SparseMatrixFormat::SparseSeq> S7(F, m, n);
		buildBySetEntry(S7, N);
		if ( testBlackbox(S7,true)  && MD.areEqual(S1,S7))
			commentator().stop("Format VVP pass");
		else {
			commentator().stop("Format VVP FAIL");
			pass = false;
		}
	}

	{ /*  SparsePar */
		// Vector of row, row is Pair of Vectors, one of indices, one of values.
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::SparsePar>", "VPV");
		SparseMatrix<Field, SparseMatrixFormat::SparsePar> S8(F, m, n);
		buildBySetEntry(S8, N);
		if ( testBlackbox(S8,true)  && MD.areEqual(S1,S8))
			commentator().stop("Format VPV pass");
		else {
			commentator().stop("Format VPV FAIL");
			pass = false;
		}
	}

	{ /*  SparseMap */
		// Vector of row, row is Map, index to value.
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::SparseMap>", "VMap");
		SparseMatrix<Field, SparseMatrixFormat::SparseMap> S9(F, m, n);
		buildBySetEntry(S9, N);
		if ( testBlackbox(S9,true)  && MD.areEqual(S1,S9))
			commentator().stop("Format VMap pass");
		else {
			commentator().stop("Format VMap FAIL");
			pass = false;
		}
	}

	{ /* TPL: Vector of i,j,val triples */
		commentator().start("SparseMatrix<Field, SparseMatrixFormat::TPL>", "TPL");
		SparseMatrix<Field, SparseMatrixFormat::TPL> S10(F, m, n);
		buildBySetEntry(S10, N);
		if ( testBlackbox(S10,true)  && MD.areEqual(S1,S10))
			commentator().stop("Format TPL pass");
		else {
			commentator().stop("Format TPL FAIL");
			pass = false;
		}

		}

	{ /*  Default OLD */
		commentator().start("SparseMatrix<Field>", "Field");
		Protected::SparseMatrixGeneric<Field> S11(F, m, n);
		buildBySetEntry(S11, N);
		if ( testBlackbox(S1,true)  && MD.areEqual(S1,S11))
			commentator().stop("SparseMatrix<Field> pass");
		else {
			commentator().stop("SparseMatrix<Field> FAIL");
			pass = false;
		}
	}

	if (pass)
		commentator().stop("Sparse matrix black box test suite pass");
	else
		commentator().stop("Sparse matrix black box test suite FAIL");

	return pass ? 0 : -1;
}

// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,:0,t0,+0,=s
// Local Variables:
// mode: C++
// tab-width: 8
// indent-tabs-mode: nil
// c-basic-offset: 8
// End:

<|endoftext|>


<commit_before>#include "pch.h"
#include "MyPin.h"

#include "AudioRenderer.h"

namespace SaneAudioRenderer
{
    MyPin::MyPin(AudioRenderer& renderer, CBaseFilter* pFilter, CAMEvent& bufferFilled, HRESULT& result)
        : CBaseInputPin(L"SaneAudioRenderer::MyPin", pFilter, this, &result, L"Input0")
        , m_bufferFilled(bufferFilled)
        , m_renderer(renderer)
    {
        if (FAILED(result))
            return;

        if (static_cast<HANDLE>(m_bufferFilled) == NULL)
            result = E_OUTOFMEMORY;
    }

    HRESULT MyPin::CheckMediaType(const CMediaType* pmt)
    {
        CheckPointer(pmt, E_POINTER);

        if (pmt->majortype == MEDIATYPE_Audio &&
            pmt->formattype == FORMAT_WaveFormatEx)
        {
            auto pFormat = reinterpret_cast<const WAVEFORMATEX*>(pmt->pbFormat);

            if (!pFormat ||
                pmt->cbFormat < sizeof(WAVEFORMATEX) ||
                pmt->cbFormat != sizeof(WAVEFORMATEX) + pFormat->cbSize)
            {
                return E_INVALIDARG;
            }

            try
            {
                if (m_renderer.CheckFormat(CopyWaveFormat(*pFormat)))
                    return S_OK;
            }
            catch (std::bad_alloc&)
            {
                return E_OUTOFMEMORY;
            }
        }

        return S_FALSE;
    }

    HRESULT MyPin::SetMediaType(const CMediaType* pmt)
    {
        assert(CritCheckIn(this));

        ReturnIfFailed(CBaseInputPin::SetMediaType(pmt));

        auto pFormat = reinterpret_cast<const WAVEFORMATEX*>(pmt->pbFormat);

        // No point in doing integrity checks, that was done in CheckMediaType().
        assert(pFormat);
        assert(pmt->cbFormat == sizeof(WAVEFORMATEX) + pFormat->cbSize);

        try
        {
            m_renderer.SetFormat(CopyWaveFormat(*pFormat));
        }
        catch (std::bad_alloc&)
        {
            return E_OUTOFMEMORY;
        }

        return S_OK;
    }

    HRESULT MyPin::CompleteConnect(IPin* pPin)
    {
        assert(CritCheckIn(this));

        IAMGraphStreamsPtr graphStreams;
        IAMPushSourcePtr pushSource;
        if (SUCCEEDED(m_pFilter->GetFilterGraph()->QueryInterface(IID_PPV_ARGS(&graphStreams))) &&
            SUCCEEDED(graphStreams->FindUpstreamInterface(pPin, IID_PPV_ARGS(&pushSource), AM_INTF_SEARCH_OUTPUT_PIN)))
        {
            ULONG flags;
            if (SUCCEEDED(pushSource->GetPushSourceFlags(&flags)))
            {
                if (flags & AM_PUSHSOURCECAPS_INTERNAL_RM)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCECAPS_INTERNAL_RM flag");

                if (flags & AM_PUSHSOURCECAPS_NOT_LIVE)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCECAPS_NOT_LIVE flag");

                if (flags & AM_PUSHSOURCECAPS_PRIVATE_CLOCK)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCECAPS_PRIVATE_CLOCK flag");

                if (flags & AM_PUSHSOURCEREQS_USE_STREAM_CLOCK)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCEREQS_USE_STREAM_CLOCK flag");

                if (!flags)
                    DebugOut("MyPin upstream live pin has no flags");
            }
        }

        return S_OK;
    }

    STDMETHODIMP MyPin::NewSegment(REFERENCE_TIME startTime, REFERENCE_TIME stopTime, double rate)
    {
        CAutoLock objectLock(this);

        CBaseInputPin::NewSegment(startTime, stopTime, rate);
        m_renderer.NewSegment(rate);

        return S_OK;
    }

    STDMETHODIMP MyPin::Receive(IMediaSample* pSample)
    {
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            if (m_state == State_Stopped)
                return VFW_E_WRONG_STATE;

            ReturnIfNotEquals(S_OK, CBaseInputPin::Receive(pSample));

            if (m_eosUp)
                return S_FALSE;
        }

        // Raise Receive() thread priority, once.
        if (m_hReceiveThread != GetCurrentThread())
        {
            m_hReceiveThread = GetCurrentThread();
            if (GetThreadPriority(m_hReceiveThread) < THREAD_PRIORITY_ABOVE_NORMAL)
                SetThreadPriority(m_hReceiveThread, THREAD_PRIORITY_ABOVE_NORMAL);
        }

        if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)
        {
            m_renderer.Finish(false);
            ReturnIfFailed(SetMediaType(static_cast<CMediaType*>(m_SampleProps.pMediaType)));
        }

        return m_renderer.Enqueue(pSample, m_SampleProps) ? S_OK : S_FALSE;
    }

    STDMETHODIMP MyPin::EndOfStream()
    {
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            if (m_state == State_Stopped)
                return VFW_E_WRONG_STATE;

            if (m_bFlushing)
                return S_FALSE;

            m_eosUp = true;
        }

        // We ask audio renderer to block until all samples are played.
        // The method returns 'false' in case of interruption.
        bool eosDown = m_renderer.Finish(true);

        {
            CAutoLock objectLock(this);

            m_eosDown = eosDown;

            if (m_eosDown)
            {
                m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)m_pFilter);
                m_bufferFilled.Set();
            }
        }

        return S_OK;
    }

    STDMETHODIMP MyPin::BeginFlush()
    {
        // Parent method locks the object before modifying it, all is good.
        CBaseInputPin::BeginFlush();

        m_renderer.BeginFlush();

        // Barrier for any present Receive() and EndOfStream() calls.
        // Subsequent ones will be rejected because m_bFlushing == TRUE.
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            m_eosUp = false;
            m_eosDown = false;
        }

        m_hReceiveThread = NULL;

        m_renderer.EndFlush();

        return S_OK;
    }

    STDMETHODIMP MyPin::EndFlush()
    {
        // Parent method locks the object before modifying it, all is good.
        CBaseInputPin::EndFlush();

        return S_OK;
    }

    HRESULT MyPin::Active()
    {
        CAutoLock objectLock(this);

        assert(m_state != State_Paused);
        m_state = State_Paused;

        if (IsConnected())
        {
            m_renderer.Pause();
        }
        else
        {
            m_eosUp = true;
            m_eosDown = true;
        }

        return S_OK;
    }

    HRESULT MyPin::Run(REFERENCE_TIME startTime)
    {
        CAutoLock objectLock(this);

        assert(m_state == State_Paused);
        m_state = State_Running;

        if (m_eosDown)
        {
            m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)m_pFilter);
        }
        else
        {
            assert(IsConnected());
            m_renderer.Play(startTime);
        }

        return S_OK;
    }

    HRESULT MyPin::Inactive()
    {
        {
            CAutoLock objectLock(this);

            assert(m_state != State_Stopped);
            m_state = State_Stopped;

            CBaseInputPin::Inactive();
        }

        m_renderer.BeginFlush();

        // Barrier for any present Receive() and EndOfStream() calls.
        // Subsequent ones will be rejected because m_state == State_Stopped.
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            m_eosUp = false;
            m_eosDown = false;
        }

        m_hReceiveThread = NULL;

        m_renderer.Stop();
        m_renderer.EndFlush();

        return S_OK;
    }

    bool MyPin::StateTransitionFinished(uint32_t timeoutMilliseconds)
    {
        {
            CAutoLock objectLock(this);

            if (!IsConnected() || m_state == State_Stopped)
                return true;
        }

        // Don't lock the object, we don't want to block Receive() method.

        // There won't be any state transitions during the wait,
        // because MyFilter always locks itself before calling this method.

        return !!m_bufferFilled.Wait(timeoutMilliseconds);
    }
}
<commit_msg>Add receive lock to MyPin::NewSegment()<commit_after>#include "pch.h"
#include "MyPin.h"

#include "AudioRenderer.h"

namespace SaneAudioRenderer
{
    MyPin::MyPin(AudioRenderer& renderer, CBaseFilter* pFilter, CAMEvent& bufferFilled, HRESULT& result)
        : CBaseInputPin(L"SaneAudioRenderer::MyPin", pFilter, this, &result, L"Input0")
        , m_bufferFilled(bufferFilled)
        , m_renderer(renderer)
    {
        if (FAILED(result))
            return;

        if (static_cast<HANDLE>(m_bufferFilled) == NULL)
            result = E_OUTOFMEMORY;
    }

    HRESULT MyPin::CheckMediaType(const CMediaType* pmt)
    {
        CheckPointer(pmt, E_POINTER);

        if (pmt->majortype == MEDIATYPE_Audio &&
            pmt->formattype == FORMAT_WaveFormatEx)
        {
            auto pFormat = reinterpret_cast<const WAVEFORMATEX*>(pmt->pbFormat);

            if (!pFormat ||
                pmt->cbFormat < sizeof(WAVEFORMATEX) ||
                pmt->cbFormat != sizeof(WAVEFORMATEX) + pFormat->cbSize)
            {
                return E_INVALIDARG;
            }

            try
            {
                if (m_renderer.CheckFormat(CopyWaveFormat(*pFormat)))
                    return S_OK;
            }
            catch (std::bad_alloc&)
            {
                return E_OUTOFMEMORY;
            }
        }

        return S_FALSE;
    }

    HRESULT MyPin::SetMediaType(const CMediaType* pmt)
    {
        assert(CritCheckIn(this));

        ReturnIfFailed(CBaseInputPin::SetMediaType(pmt));

        auto pFormat = reinterpret_cast<const WAVEFORMATEX*>(pmt->pbFormat);

        // No point in doing integrity checks, that was done in CheckMediaType().
        assert(pFormat);
        assert(pmt->cbFormat == sizeof(WAVEFORMATEX) + pFormat->cbSize);

        try
        {
            m_renderer.SetFormat(CopyWaveFormat(*pFormat));
        }
        catch (std::bad_alloc&)
        {
            return E_OUTOFMEMORY;
        }

        return S_OK;
    }

    HRESULT MyPin::CompleteConnect(IPin* pPin)
    {
        assert(CritCheckIn(this));

        IAMGraphStreamsPtr graphStreams;
        IAMPushSourcePtr pushSource;
        if (SUCCEEDED(m_pFilter->GetFilterGraph()->QueryInterface(IID_PPV_ARGS(&graphStreams))) &&
            SUCCEEDED(graphStreams->FindUpstreamInterface(pPin, IID_PPV_ARGS(&pushSource), AM_INTF_SEARCH_OUTPUT_PIN)))
        {
            ULONG flags;
            if (SUCCEEDED(pushSource->GetPushSourceFlags(&flags)))
            {
                if (flags & AM_PUSHSOURCECAPS_INTERNAL_RM)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCECAPS_INTERNAL_RM flag");

                if (flags & AM_PUSHSOURCECAPS_NOT_LIVE)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCECAPS_NOT_LIVE flag");

                if (flags & AM_PUSHSOURCECAPS_PRIVATE_CLOCK)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCECAPS_PRIVATE_CLOCK flag");

                if (flags & AM_PUSHSOURCEREQS_USE_STREAM_CLOCK)
                    DebugOut("MyPin upstream live pin has AM_PUSHSOURCEREQS_USE_STREAM_CLOCK flag");

                if (!flags)
                    DebugOut("MyPin upstream live pin has no flags");
            }
        }

        return S_OK;
    }

    STDMETHODIMP MyPin::NewSegment(REFERENCE_TIME startTime, REFERENCE_TIME stopTime, double rate)
    {
        CAutoLock receiveLock(&m_receiveMutex);
        CAutoLock objectLock(this);

        CBaseInputPin::NewSegment(startTime, stopTime, rate);
        m_renderer.NewSegment(rate);

        return S_OK;
    }

    STDMETHODIMP MyPin::Receive(IMediaSample* pSample)
    {
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            if (m_state == State_Stopped)
                return VFW_E_WRONG_STATE;

            ReturnIfNotEquals(S_OK, CBaseInputPin::Receive(pSample));

            if (m_eosUp)
                return S_FALSE;
        }

        // Raise Receive() thread priority, once.
        if (m_hReceiveThread != GetCurrentThread())
        {
            m_hReceiveThread = GetCurrentThread();
            if (GetThreadPriority(m_hReceiveThread) < THREAD_PRIORITY_ABOVE_NORMAL)
                SetThreadPriority(m_hReceiveThread, THREAD_PRIORITY_ABOVE_NORMAL);
        }

        if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)
        {
            m_renderer.Finish(false);
            ReturnIfFailed(SetMediaType(static_cast<CMediaType*>(m_SampleProps.pMediaType)));
        }

        return m_renderer.Enqueue(pSample, m_SampleProps) ? S_OK : S_FALSE;
    }

    STDMETHODIMP MyPin::EndOfStream()
    {
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            if (m_state == State_Stopped)
                return VFW_E_WRONG_STATE;

            if (m_bFlushing)
                return S_FALSE;

            m_eosUp = true;
        }

        // We ask audio renderer to block until all samples are played.
        // The method returns 'false' in case of interruption.
        bool eosDown = m_renderer.Finish(true);

        {
            CAutoLock objectLock(this);

            m_eosDown = eosDown;

            if (m_eosDown)
            {
                m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)m_pFilter);
                m_bufferFilled.Set();
            }
        }

        return S_OK;
    }

    STDMETHODIMP MyPin::BeginFlush()
    {
        // Parent method locks the object before modifying it, all is good.
        CBaseInputPin::BeginFlush();

        m_renderer.BeginFlush();

        // Barrier for any present Receive() and EndOfStream() calls.
        // Subsequent ones will be rejected because m_bFlushing == TRUE.
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            m_eosUp = false;
            m_eosDown = false;
        }

        m_hReceiveThread = NULL;

        m_renderer.EndFlush();

        return S_OK;
    }

    STDMETHODIMP MyPin::EndFlush()
    {
        // Parent method locks the object before modifying it, all is good.
        CBaseInputPin::EndFlush();

        return S_OK;
    }

    HRESULT MyPin::Active()
    {
        CAutoLock objectLock(this);

        assert(m_state != State_Paused);
        m_state = State_Paused;

        if (IsConnected())
        {
            m_renderer.Pause();
        }
        else
        {
            m_eosUp = true;
            m_eosDown = true;
        }

        return S_OK;
    }

    HRESULT MyPin::Run(REFERENCE_TIME startTime)
    {
        CAutoLock objectLock(this);

        assert(m_state == State_Paused);
        m_state = State_Running;

        if (m_eosDown)
        {
            m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)m_pFilter);
        }
        else
        {
            assert(IsConnected());
            m_renderer.Play(startTime);
        }

        return S_OK;
    }

    HRESULT MyPin::Inactive()
    {
        {
            CAutoLock objectLock(this);

            assert(m_state != State_Stopped);
            m_state = State_Stopped;

            CBaseInputPin::Inactive();
        }

        m_renderer.BeginFlush();

        // Barrier for any present Receive() and EndOfStream() calls.
        // Subsequent ones will be rejected because m_state == State_Stopped.
        CAutoLock receiveLock(&m_receiveMutex);

        {
            CAutoLock objectLock(this);

            m_eosUp = false;
            m_eosDown = false;
        }

        m_hReceiveThread = NULL;

        m_renderer.Stop();
        m_renderer.EndFlush();

        return S_OK;
    }

    bool MyPin::StateTransitionFinished(uint32_t timeoutMilliseconds)
    {
        {
            CAutoLock objectLock(this);

            if (!IsConnected() || m_state == State_Stopped)
                return true;
        }

        // Don't lock the object, we don't want to block Receive() method.

        // There won't be any state transitions during the wait,
        // because MyFilter always locks itself before calling this method.

        return !!m_bufferFilled.Wait(timeoutMilliseconds);
    }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <vector>
#include "Options.h"
#include "capture.h"
#include "xalt_config.h"
#include "base64.h"

double convert_double(const char* name, const char* s)
{
  char  *p;
  double v;

  v = strtod(s, &p);
  if (p == s || *p)
    {
      fprintf(stderr,"For option: \"%s\", unable to parse: \"%s\"\n", name, s);
      exit(1);
    }
  return v;
}

long convert_long(const char* name, const char* s)
{
  char *p;
  long  v;

  v = strtol(s, &p, 10);
  if (p == s || *p)
    {
      fprintf(stderr,"For option: \"%s\", unable to parse: \"%s\"\n", name, s);
      exit(1);
    }
  return v;
}

Options::Options(int argc, char** argv)
  : m_start(0.0), m_end(0.0), m_ntasks(1L), m_ngpus(0L),
    m_interfaceV(0L),         m_ppid(0L),
    m_syshost("unknown"),     m_uuid("unknown"),
    m_exec("unknown"),        m_userCmdLine("[]"),
    m_exec_type("unknown"),   m_confFn("xalt_db.conf")
{
  int   c;

  while(1)
    {
      int option_index       = 0;
      static struct option long_options[] = {
        {"interfaceV", required_argument, NULL, 'V'},
        {"start",      required_argument, NULL, 's'},
        {"end",        required_argument, NULL, 'e'},
        {"syshost",    required_argument, NULL, 'h'},
        {"exec",       required_argument, NULL, 'x'},
        {"ntasks",     required_argument, NULL, 'n'},
        {"ngpus",      required_argument, NULL, 'g'},
        {"uuid",       required_argument, NULL, 'u'},
        {"confFn",     required_argument, NULL, 'c'},
        {"ppid",       required_argument, NULL, 'p'},
        {"path",       required_argument, NULL, 'P'},
        {"prob",       required_argument, NULL, 'b'},
        {"ld_libpath", required_argument, NULL, 'L'},
        {0,         0,                 0,     0 }
      };

      c = getopt_long(argc, argv, "c:s:e:h:x:n:g:u:p:P:L:",
		      long_options, &option_index);

      if (c == -1)
	break;

      switch(c)
	{
        case 'V':
          if (optarg)
            m_interfaceV = (pid_t) convert_long("ppid", optarg);
          break;
        case 'p':
          if (optarg)
            m_ppid = (pid_t) convert_long("ppid", optarg);
          break;
        case 'b':
          if (optarg)
            m_probability = convert_double("prob", optarg);
          break;
	case 's':
          if (optarg)
            m_start = convert_double("start", optarg);
	  break;
	case 'e':
          if (optarg)
            m_end = convert_double("end", optarg);
	  break;
	case 'c':
          if (optarg)
            m_confFn = optarg;
	  break;
	case 'h':
          if (optarg)
            m_syshost = optarg;
	  break;
        case 'x':
          if (optarg)
            m_exec = optarg;
	  break;
	case 'n':
          if (optarg)
            m_ntasks = convert_long("ntasks", optarg);
	  break;
	case 'g':
          if (optarg)
            m_ngpus = convert_long("ngpus", optarg);
	  break;
        case 'u':
          if (optarg)
            m_uuid = optarg;
	  break;
        case 'P':
          if (optarg)
            m_path = optarg;
	  break;
        case 'L':
          if (optarg)
            m_ldLibPath = optarg;
	  break;
	case '?':
	  printf("Huh?\n");
	  break;
	default:
	  printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

  HERE;
  if (optind + 1 == argc && argv[optind][0] == '[')
    m_userCmdLine = argv[optind];
  else if (optind < argc)
    {
      if (m_interfaceV < 4)
        {
          m_userCmdLine = "[";
          for (int i = optind; i < argc; ++i)
            {
              m_userCmdLine += "\"";
              m_userCmdLine += argv[i];
              m_userCmdLine += "\",";
            }
          if (m_userCmdLine.back() == ',')
            m_userCmdLine.replace(m_userCmdLine.size()-1,1,"]");
        }
      else
        {
          HERE;
          int   jLen;
          fprintf(stderr,"len: %ld, b64_cmd: %s\n",strlen(argv[optind]),argv[optind]);

          char* decoded = reinterpret_cast<char*>(base64_decode(argv[optind], strlen(argv[optind]), &jLen));
          m_userCmdLine = decoded;
          HERE;
          free(decoded);
          HERE;
        }
    }

  HERE;
  if (m_exec != "unknown")
    {
      std::vector<std::string> result;
      std::string              cmd;

      cmd = PATH_TO_PRGM_FILE " " + m_exec;
      capture(cmd, result);
      if (result[0].find("script") != std::string::npos ||
          result[0].find("text")   != std::string::npos)
        m_exec_type = "script";
      else
        m_exec_type = "binary";
    }
  HERE;
}
<commit_msg>debugging xalt_run_submision 4<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <vector>
#include "Options.h"
#include "capture.h"
#include "xalt_config.h"
#include "base64.h"

double convert_double(const char* name, const char* s)
{
  char  *p;
  double v;

  v = strtod(s, &p);
  if (p == s || *p)
    {
      fprintf(stderr,"For option: \"%s\", unable to parse: \"%s\"\n", name, s);
      exit(1);
    }
  return v;
}

long convert_long(const char* name, const char* s)
{
  char *p;
  long  v;

  v = strtol(s, &p, 10);
  if (p == s || *p)
    {
      fprintf(stderr,"For option: \"%s\", unable to parse: \"%s\"\n", name, s);
      exit(1);
    }
  return v;
}

Options::Options(int argc, char** argv)
  : m_start(0.0), m_end(0.0), m_ntasks(1L), m_ngpus(0L),
    m_interfaceV(0L),         m_ppid(0L),
    m_syshost("unknown"),     m_uuid("unknown"),
    m_exec("unknown"),        m_userCmdLine("[]"),
    m_exec_type("unknown"),   m_confFn("xalt_db.conf")
{
  int   c;

  while(1)
    {
      int option_index       = 0;
      static struct option long_options[] = {
        {"interfaceV", required_argument, NULL, 'V'},
        {"start",      required_argument, NULL, 's'},
        {"end",        required_argument, NULL, 'e'},
        {"syshost",    required_argument, NULL, 'h'},
        {"exec",       required_argument, NULL, 'x'},
        {"ntasks",     required_argument, NULL, 'n'},
        {"ngpus",      required_argument, NULL, 'g'},
        {"uuid",       required_argument, NULL, 'u'},
        {"confFn",     required_argument, NULL, 'c'},
        {"ppid",       required_argument, NULL, 'p'},
        {"path",       required_argument, NULL, 'P'},
        {"prob",       required_argument, NULL, 'b'},
        {"ld_libpath", required_argument, NULL, 'L'},
        {0,         0,                 0,     0 }
      };

      c = getopt_long(argc, argv, "c:s:e:h:x:n:g:u:p:P:L:",
		      long_options, &option_index);

      if (c == -1)
	break;

      switch(c)
	{
        case 'V':
          if (optarg)
            m_interfaceV = (pid_t) convert_long("ppid", optarg);
          break;
        case 'p':
          if (optarg)
            m_ppid = (pid_t) convert_long("ppid", optarg);
          break;
        case 'b':
          if (optarg)
            m_probability = convert_double("prob", optarg);
          break;
	case 's':
          if (optarg)
            m_start = convert_double("start", optarg);
	  break;
	case 'e':
          if (optarg)
            m_end = convert_double("end", optarg);
	  break;
	case 'c':
          if (optarg)
            m_confFn = optarg;
	  break;
	case 'h':
          if (optarg)
            m_syshost = optarg;
	  break;
        case 'x':
          if (optarg)
            m_exec = optarg;
	  break;
	case 'n':
          if (optarg)
            m_ntasks = convert_long("ntasks", optarg);
	  break;
	case 'g':
          if (optarg)
            m_ngpus = convert_long("ngpus", optarg);
	  break;
        case 'u':
          if (optarg)
            m_uuid = optarg;
	  break;
        case 'P':
          if (optarg)
            m_path = optarg;
	  break;
        case 'L':
          if (optarg)
            m_ldLibPath = optarg;
	  break;
	case '?':
	  printf("Huh?\n");
	  break;
	default:
	  printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

  HERE;
  if (optind + 1 == argc && argv[optind][0] == '[')
    m_userCmdLine = argv[optind];
  else if (optind < argc)
    {
      if (m_interfaceV < 4)
        {
          m_userCmdLine = "[";
          for (int i = optind; i < argc; ++i)
            {
              m_userCmdLine += "\"";
              m_userCmdLine += argv[i];
              m_userCmdLine += "\",";
            }
          if (m_userCmdLine.back() == ',')
            m_userCmdLine.replace(m_userCmdLine.size()-1,1,"]");
        }
      else
        {
          HERE;
          int   jLen;
          fprintf(stderr,"len: %ld, b64_cmd: %s\n",strlen(argv[optind]),argv[optind]);

          HERE;
          char* decoded = reinterpret_cast<char*>(base64_decode(argv[optind], strlen(argv[optind]), &jLen));
          HERE;
          m_userCmdLine = decoded;
          HERE;
          free(decoded);
          HERE;
        }
    }

  HERE;
  if (m_exec != "unknown")
    {
      std::vector<std::string> result;
      std::string              cmd;

      cmd = PATH_TO_PRGM_FILE " " + m_exec;
      capture(cmd, result);
      if (result[0].find("script") != std::string::npos ||
          result[0].find("text")   != std::string::npos)
        m_exec_type = "script";
      else
        m_exec_type = "binary";
    }
  HERE;
}
<|endoftext|>


<commit_before>// Copyright 2017 Paul Nettle.
//
// This file is part of Gobbledegook.
//
// Gobbledegook is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gobbledegook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gobbledegook.  If not, see <http://www.gnu.org/licenses/>.

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// >>
// >>>  INSIDE THIS FILE
// >>
//
// This file contains various general utilitarian functions used throught. It is in some ways, the 'junk drawer' of the appliation,
// though better organized than most physical junk drawers.
//
// >>
// >>>  DISCUSSION
// >>
//
// This file contains:
//
//     - String helper functions (trimming methods)
//     - Hexidecimal helper functions for
//       + Producing hex values of various types (8-bit, 16-bit, 32-bit)
//       + Standardied Hex/ASCII dumps to the log file of chunks of binary data
//       + Properly formatted Bluetooth addresses)
//     - GVariant helper funcions of various forms to convert values to/from GVariants
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <algorithm>
#include <string.h>

#include "Utils.h"

// ---------------------------------------------------------------------------------------------------------------------------------
// Handy string functions
// ---------------------------------------------------------------------------------------------------------------------------------

// Trim from start (in place)
void Utils::trimBeginInPlace(std::string &str)
{
    str.erase(str.begin(), std::find_if(str.begin(), str.end(),
    [](int ch)
    {
        return !std::isspace(ch);
    }));
}

// Trim from end (in place)
void Utils::trimEndInPlace(std::string &str)
{
    str.erase(std::find_if(str.rbegin(), str.rend(),
    [](int ch)
    {
        return !std::isspace(ch);
    }).base(), str.end());
}

// Trim from both ends (in place)
void Utils::trimInPlace(std::string &str)
{
    trimBeginInPlace(str);
    trimEndInPlace(str);
}

// Trim from start (copying)
std::string Utils::trimBegin(const std::string &str)
{
	std::string out = str;
    trimBeginInPlace(out);
    return out;
}

// Trim from end (copying)
std::string Utils::trimEnd(const std::string &str)
{
	std::string out = str;
    trimEndInPlace(out);
    return out;
}

// Trim from both ends (copying)
std::string Utils::trim(const std::string &str)
{
	std::string out = str;
    trimInPlace(out);
    return out;
}

// ---------------------------------------------------------------------------------------------------------------------------------
// Hex output functions
// ---------------------------------------------------------------------------------------------------------------------------------

// Returns a zero-padded 8-bit hex value in the format: 0xA
std::string Utils::hex(uint8_t value)
{
	char hex[16];
	sprintf(hex, "0x%02X", value);
	return hex;
}

// Returns a zero-padded 8-bit hex value in the format: 0xAB
std::string Utils::hex(uint16_t value)
{
	char hex[16];
	sprintf(hex, "0x%04X", value);
	return hex;
}

// Returns a zero-padded 8-bit hex value in the format: 0xABCD
std::string Utils::hex(uint32_t value)
{
	char hex[16];
	sprintf(hex, "0x%08X", value);
	return hex;
}

// A full hex-dump of binary data (with accompanying ASCII output)
std::string Utils::hex(const uint8_t *pData, int count)
{
	char hex[16];

	// Hex data output
	std::string line;
	std::vector<std::string> hexData;
	for (int i = 0; i < count; ++i)
	{
		sprintf(hex, "%02X ", pData[i]);
		line += hex;

		if (line.length() >= 16 * 3)
		{
			hexData.push_back(line);
			line = "";
		}
	}

	if (!line.empty())
	{
		hexData.push_back(line);
		line = "";
	}

	// ASCII data output
	std::vector<std::string> asciiData;
	for (int i = 0; i < count; ++i)
	{
		// Unprintable?
		if (pData[i] < 0x20 || pData[i] > 0x7e)
		{
			line += ".";
		}
		else
		{
			line += pData[i];
		}

		if (line.length() >= 16)
		{
			asciiData.push_back(line);
			line = "";
		}
	}

	if (!line.empty())
	{
		asciiData.push_back(line);
	}

	std::string result = "\n";
	size_t dataSize = hexData.size();
	for (size_t i = 0; i < dataSize; ++i)
	{
		std::string hexPart = hexData[i];
		hexPart.insert(hexPart.length(), 48-hexPart.length(), ' ');

		std::string asciiPart = asciiData[i];
		asciiPart.insert(asciiPart.length(), 16-asciiPart.length(), ' ');

		result += std::string("    > ") + hexPart + "   [" + asciiPart + "]";

		if (i < dataSize - 1) { result += "\n"; }
	}

	return result;
}

// Returns a peoperly formatted Bluetooth address from a set of six octets stored at `pAddress`
//
// USE WITH CAUTION: It is expected that pAddress point to an array of 6 bytes. The length of the array cannot be validated and
// incorrect lengths will produce undefined, likely unwanted and potentially fatal results. Or it will return the address of the
// train at platform 9 3/4. You decide.
//
// This method returns a set of six zero-padded 8-bit hex values 8-bit in the format: 12:34:56:78:9A:BC
std::string Utils::bluetoothAddressString(uint8_t *pAddress)
{
	char hex[32];
	snprintf(hex, sizeof(hex), "%02X:%02X:%02X:%02X:%02X:%02X",
		pAddress[0], pAddress[1], pAddress[2], pAddress[3], pAddress[4], pAddress[5]);
	return hex;
}

// ---------------------------------------------------------------------------------------------------------------------------------
// GVariant helper functions
// ---------------------------------------------------------------------------------------------------------------------------------

// Returns a GVariant containing a floating reference to a utf8 string
GVariant *Utils::gvariantFromString(const char *pStr)
{
	return g_variant_new_string(pStr);
}

// Returns a GVariant containing a floating reference to a utf8 string
GVariant *Utils::gvariantFromString(const std::string &str)
{
	return g_variant_new_string(str.c_str());
}

// Returns an array of strings ("as") with one string per variable argument.
//
// The array must be terminated with a nullptr.
//
// This is an extension method to the vararg version, which accepts pass-through variable arguments from other mthods.
GVariant *Utils::gvariantFromStringArray(const char *pStr, va_list args)
{
	// Deal with empty arrays
	if (pStr == 0)
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	while(nullptr != pStr)
	{
		g_variant_builder_add(&builder, "s", pStr);
		pStr = va_arg(args, const char *);
	}

	return g_variant_builder_end(&builder);
}

// Returns an array of strings ("as") with one string per variable argument.
//
// The array must be terminated with a nullptr.
GVariant *Utils::gvariantFromStringArray(const char *pStr, ...)
{
	// Deal with empty arrays
	if (pStr == 0)
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	va_list args;
	va_start(args, pStr);

	GVariant *pResult = gvariantFromStringArray(pStr, args);

	va_end(args);

	return pResult;
}

// Returns an array of strings ("as") from an array of strings
GVariant *Utils::gvariantFromStringArray(const std::vector<std::string> &arr)
{
	// Deal with empty arrays
	if (arr.empty())
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	for (std::string str : arr)
	{
		g_variant_builder_add(&builder, "s", str.c_str());
	}

	return g_variant_builder_end(&builder);
}

// Returns an array of strings ("as") from an array of C strings
GVariant *Utils::gvariantFromStringArray(const std::vector<const char *> &arr)
{
	// Deal with empty arrays
	if (arr.empty())
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	for (const char *pStr : arr)
	{
		g_variant_builder_add(&builder, "s", pStr);
	}

	return g_variant_builder_end(&builder);
}

// Returns an GVariant* containing an object path ("o") from an DBusObjectPath
GVariant *Utils::gvariantFromObject(const DBusObjectPath &path)
{
	return g_variant_new_object_path(path.c_str());
}

// Returns an GVariant* containing a boolean
GVariant *Utils::gvariantFromBoolean(bool b)
{
	return g_variant_new_boolean(b);
}

// Returns an GVariant* containing a 16-bit integer
GVariant *Utils::gvariantFromInt(gint16 value)
{
	return g_variant_new_int16(value);
}

// Returns an GVariant* containing a 32-bit integer
GVariant *Utils::gvariantFromInt(gint32 value)
{
	return g_variant_new_int32(value);
}

// Returns an array of bytes ("ay") with the contents of the input C string
GVariant *Utils::gvariantFromByteArray(const char *pStr)
{
	// Deal with empty arrays
	if (*pStr == 0)
	{
		return g_variant_new("ay", nullptr);
	}

	return g_variant_new_bytestring(pStr);
}

// Returns an array of bytes ("ay") with the contents of the input string
GVariant *Utils::gvariantFromByteArray(const std::string &str)
{
	return gvariantFromByteArray(str.c_str());
}

// Returns an array of bytes ("ay") with the contents of the input array of unsigned 8-bit values
GVariant *Utils::gvariantFromByteArray(const guint8 *pBytes, int count)
{
	GBytes *pGbytes = g_bytes_new(pBytes, count);
	return g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, pGbytes, count);
}

// Returns an array of bytes ("ay") with the contents of the input array of unsigned 8-bit values
GVariant *Utils::gvariantFromByteArray(const std::vector<guint8> bytes)
{
	GBytes *pGbytes = g_bytes_new(bytes.data(), bytes.size());
	return g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, pGbytes, bytes.size());
}

// Returns an array of bytes ("ay") containing a single unsigned 8-bit value
GVariant *Utils::gvariantFromByteArray(const guint8 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 8-bit value
GVariant *Utils::gvariantFromByteArray(const gint8 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single unsigned 16-bit value
GVariant *Utils::gvariantFromByteArray(const guint16 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 16-bit value
GVariant *Utils::gvariantFromByteArray(const gint16 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single unsigned 32-bit value
GVariant *Utils::gvariantFromByteArray(const guint32 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 32-bit value
GVariant *Utils::gvariantFromByteArray(const gint32 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single unsigned 64-bit value
GVariant *Utils::gvariantFromByteArray(const guint64 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 64-bit value
GVariant *Utils::gvariantFromByteArray(const gint64 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Extracts a string from an array of bytes ("ay")
std::string Utils::stringFromGVariantByteArray(const GVariant *pVariant)
{
	gsize size;
	gconstpointer pPtr = g_variant_get_fixed_array(const_cast<GVariant *>(pVariant), &size, 1);
	std::vector<gchar> array(size + 1, 0);
	memcpy(array.data(), pPtr, size);
	return array.data();
}
<commit_msg>Removed null-terminators from strings being built into Variants as byte arrays.<commit_after>// Copyright 2017 Paul Nettle.
//
// This file is part of Gobbledegook.
//
// Gobbledegook is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gobbledegook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gobbledegook.  If not, see <http://www.gnu.org/licenses/>.

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// >>
// >>>  INSIDE THIS FILE
// >>
//
// This file contains various general utilitarian functions used throught. It is in some ways, the 'junk drawer' of the appliation,
// though better organized than most physical junk drawers.
//
// >>
// >>>  DISCUSSION
// >>
//
// This file contains:
//
//     - String helper functions (trimming methods)
//     - Hexidecimal helper functions for
//       + Producing hex values of various types (8-bit, 16-bit, 32-bit)
//       + Standardied Hex/ASCII dumps to the log file of chunks of binary data
//       + Properly formatted Bluetooth addresses)
//     - GVariant helper funcions of various forms to convert values to/from GVariants
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <algorithm>
#include <string.h>

#include "Utils.h"

// ---------------------------------------------------------------------------------------------------------------------------------
// Handy string functions
// ---------------------------------------------------------------------------------------------------------------------------------

// Trim from start (in place)
void Utils::trimBeginInPlace(std::string &str)
{
    str.erase(str.begin(), std::find_if(str.begin(), str.end(),
    [](int ch)
    {
        return !std::isspace(ch);
    }));
}

// Trim from end (in place)
void Utils::trimEndInPlace(std::string &str)
{
    str.erase(std::find_if(str.rbegin(), str.rend(),
    [](int ch)
    {
        return !std::isspace(ch);
    }).base(), str.end());
}

// Trim from both ends (in place)
void Utils::trimInPlace(std::string &str)
{
    trimBeginInPlace(str);
    trimEndInPlace(str);
}

// Trim from start (copying)
std::string Utils::trimBegin(const std::string &str)
{
	std::string out = str;
    trimBeginInPlace(out);
    return out;
}

// Trim from end (copying)
std::string Utils::trimEnd(const std::string &str)
{
	std::string out = str;
    trimEndInPlace(out);
    return out;
}

// Trim from both ends (copying)
std::string Utils::trim(const std::string &str)
{
	std::string out = str;
    trimInPlace(out);
    return out;
}

// ---------------------------------------------------------------------------------------------------------------------------------
// Hex output functions
// ---------------------------------------------------------------------------------------------------------------------------------

// Returns a zero-padded 8-bit hex value in the format: 0xA
std::string Utils::hex(uint8_t value)
{
	char hex[16];
	sprintf(hex, "0x%02X", value);
	return hex;
}

// Returns a zero-padded 8-bit hex value in the format: 0xAB
std::string Utils::hex(uint16_t value)
{
	char hex[16];
	sprintf(hex, "0x%04X", value);
	return hex;
}

// Returns a zero-padded 8-bit hex value in the format: 0xABCD
std::string Utils::hex(uint32_t value)
{
	char hex[16];
	sprintf(hex, "0x%08X", value);
	return hex;
}

// A full hex-dump of binary data (with accompanying ASCII output)
std::string Utils::hex(const uint8_t *pData, int count)
{
	char hex[16];

	// Hex data output
	std::string line;
	std::vector<std::string> hexData;
	for (int i = 0; i < count; ++i)
	{
		sprintf(hex, "%02X ", pData[i]);
		line += hex;

		if (line.length() >= 16 * 3)
		{
			hexData.push_back(line);
			line = "";
		}
	}

	if (!line.empty())
	{
		hexData.push_back(line);
		line = "";
	}

	// ASCII data output
	std::vector<std::string> asciiData;
	for (int i = 0; i < count; ++i)
	{
		// Unprintable?
		if (pData[i] < 0x20 || pData[i] > 0x7e)
		{
			line += ".";
		}
		else
		{
			line += pData[i];
		}

		if (line.length() >= 16)
		{
			asciiData.push_back(line);
			line = "";
		}
	}

	if (!line.empty())
	{
		asciiData.push_back(line);
	}

	std::string result = "\n";
	size_t dataSize = hexData.size();
	for (size_t i = 0; i < dataSize; ++i)
	{
		std::string hexPart = hexData[i];
		hexPart.insert(hexPart.length(), 48-hexPart.length(), ' ');

		std::string asciiPart = asciiData[i];
		asciiPart.insert(asciiPart.length(), 16-asciiPart.length(), ' ');

		result += std::string("    > ") + hexPart + "   [" + asciiPart + "]";

		if (i < dataSize - 1) { result += "\n"; }
	}

	return result;
}

// Returns a peoperly formatted Bluetooth address from a set of six octets stored at `pAddress`
//
// USE WITH CAUTION: It is expected that pAddress point to an array of 6 bytes. The length of the array cannot be validated and
// incorrect lengths will produce undefined, likely unwanted and potentially fatal results. Or it will return the address of the
// train at platform 9 3/4. You decide.
//
// This method returns a set of six zero-padded 8-bit hex values 8-bit in the format: 12:34:56:78:9A:BC
std::string Utils::bluetoothAddressString(uint8_t *pAddress)
{
	char hex[32];
	snprintf(hex, sizeof(hex), "%02X:%02X:%02X:%02X:%02X:%02X",
		pAddress[0], pAddress[1], pAddress[2], pAddress[3], pAddress[4], pAddress[5]);
	return hex;
}

// ---------------------------------------------------------------------------------------------------------------------------------
// GVariant helper functions
// ---------------------------------------------------------------------------------------------------------------------------------

// Returns a GVariant containing a floating reference to a utf8 string
GVariant *Utils::gvariantFromString(const char *pStr)
{
	return g_variant_new_string(pStr);
}

// Returns a GVariant containing a floating reference to a utf8 string
GVariant *Utils::gvariantFromString(const std::string &str)
{
	return g_variant_new_string(str.c_str());
}

// Returns an array of strings ("as") with one string per variable argument.
//
// The array must be terminated with a nullptr.
//
// This is an extension method to the vararg version, which accepts pass-through variable arguments from other mthods.
GVariant *Utils::gvariantFromStringArray(const char *pStr, va_list args)
{
	// Deal with empty arrays
	if (pStr == 0)
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	while(nullptr != pStr)
	{
		g_variant_builder_add(&builder, "s", pStr);
		pStr = va_arg(args, const char *);
	}

	return g_variant_builder_end(&builder);
}

// Returns an array of strings ("as") with one string per variable argument.
//
// The array must be terminated with a nullptr.
GVariant *Utils::gvariantFromStringArray(const char *pStr, ...)
{
	// Deal with empty arrays
	if (pStr == 0)
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	va_list args;
	va_start(args, pStr);

	GVariant *pResult = gvariantFromStringArray(pStr, args);

	va_end(args);

	return pResult;
}

// Returns an array of strings ("as") from an array of strings
GVariant *Utils::gvariantFromStringArray(const std::vector<std::string> &arr)
{
	// Deal with empty arrays
	if (arr.empty())
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	for (std::string str : arr)
	{
		g_variant_builder_add(&builder, "s", str.c_str());
	}

	return g_variant_builder_end(&builder);
}

// Returns an array of strings ("as") from an array of C strings
GVariant *Utils::gvariantFromStringArray(const std::vector<const char *> &arr)
{
	// Deal with empty arrays
	if (arr.empty())
	{
		return g_variant_new("as", nullptr);
	}

	g_auto(GVariantBuilder) builder;
	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

	for (const char *pStr : arr)
	{
		g_variant_builder_add(&builder, "s", pStr);
	}

	return g_variant_builder_end(&builder);
}

// Returns an GVariant* containing an object path ("o") from an DBusObjectPath
GVariant *Utils::gvariantFromObject(const DBusObjectPath &path)
{
	return g_variant_new_object_path(path.c_str());
}

// Returns an GVariant* containing a boolean
GVariant *Utils::gvariantFromBoolean(bool b)
{
	return g_variant_new_boolean(b);
}

// Returns an GVariant* containing a 16-bit integer
GVariant *Utils::gvariantFromInt(gint16 value)
{
	return g_variant_new_int16(value);
}

// Returns an GVariant* containing a 32-bit integer
GVariant *Utils::gvariantFromInt(gint32 value)
{
	return g_variant_new_int32(value);
}

// Returns an array of bytes ("ay") with the contents of the input C string
GVariant *Utils::gvariantFromByteArray(const char *pStr)
{
	// Deal with empty arrays
	if (*pStr == 0)
	{
		return g_variant_new("ay", nullptr);
	}

	return gvariantFromByteArray(reinterpret_cast<const guint8 *>(pStr), strlen(pStr));
}

// Returns an array of bytes ("ay") with the contents of the input string
GVariant *Utils::gvariantFromByteArray(const std::string &str)
{
	return gvariantFromByteArray(reinterpret_cast<const guint8 *>(str.c_str()), str.length());
}

// Returns an array of bytes ("ay") with the contents of the input array of unsigned 8-bit values
GVariant *Utils::gvariantFromByteArray(const guint8 *pBytes, int count)
{
	GBytes *pGbytes = g_bytes_new(pBytes, count);
	return g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, pGbytes, count);
}

// Returns an array of bytes ("ay") with the contents of the input array of unsigned 8-bit values
GVariant *Utils::gvariantFromByteArray(const std::vector<guint8> bytes)
{
	GBytes *pGbytes = g_bytes_new(bytes.data(), bytes.size());
	return g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, pGbytes, bytes.size());
}

// Returns an array of bytes ("ay") containing a single unsigned 8-bit value
GVariant *Utils::gvariantFromByteArray(const guint8 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 8-bit value
GVariant *Utils::gvariantFromByteArray(const gint8 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single unsigned 16-bit value
GVariant *Utils::gvariantFromByteArray(const guint16 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 16-bit value
GVariant *Utils::gvariantFromByteArray(const gint16 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single unsigned 32-bit value
GVariant *Utils::gvariantFromByteArray(const guint32 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 32-bit value
GVariant *Utils::gvariantFromByteArray(const gint32 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single unsigned 64-bit value
GVariant *Utils::gvariantFromByteArray(const guint64 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Returns an array of bytes ("ay") containing a single signed 64-bit value
GVariant *Utils::gvariantFromByteArray(const gint64 data)
{
	return gvariantFromByteArray((const guint8 *) &data, sizeof(data));
}

// Extracts a string from an array of bytes ("ay")
std::string Utils::stringFromGVariantByteArray(const GVariant *pVariant)
{
	gsize size;
	gconstpointer pPtr = g_variant_get_fixed_array(const_cast<GVariant *>(pVariant), &size, 1);
	std::vector<gchar> array(size + 1, 0);
	memcpy(array.data(), pPtr, size);
	return array.data();
}
<|endoftext|>


<commit_before>#include <string.h>
#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct XYPad : Module {
	enum ParamIds {
		X_POS_PARAM,
		Y_POS_PARAM,
		GATE_PARAM,
		OFFSET_X_VOLTS_PARAM,
		OFFSET_Y_VOLTS_PARAM,
		SCALE_PARAM,
		AUTO_PLAY_PARAM,
		NUM_PARAMS
	};
	enum InputIds {
		PLAY_GATE_INPUT,
		NUM_INPUTS
	};
	enum OutputIds {
		X_OUTPUT,
		Y_OUTPUT,
		X_INV_OUTPUT,
		Y_INV_OUTPUT,
		GATE_OUTPUT,
		NUM_OUTPUTS
	};

	float minX = 0, minY = 0, maxX = 0, maxY = 0;
	float displayWidth = 0, displayHeight = 0;
	float totalBallSize = 12;
	float minVolt = -5, maxVolt = 5;
	float repeatLight = 0.0;
	float phase = 0.0;
	bool autoPlayOn = false;
	bool playing = false;
	bool mouseDown = false;
	SchmittTrigger autoBtnTrigger;
	SchmittTrigger playbackTrigger;
	std::vector<Vec> points;
	int curPointIdx = 0;

	XYPad() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
	void step();
	void initialize(){
		defaultPos();
	}

	json_t *toJson() {
		json_t *rootJ = json_object();
		json_object_set_new(rootJ, "xPos", json_real(params[X_POS_PARAM].value));
		json_object_set_new(rootJ, "yPos", json_real(params[Y_POS_PARAM].value));
		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		json_t *xPosJ = json_object_get(rootJ, "xPos");
		json_t *yPosJ = json_object_get(rootJ, "yPos");
		if (xPosJ){ params[X_POS_PARAM].value = json_real_value(xPosJ); }
		if (yPosJ){ params[Y_POS_PARAM].value = json_real_value(yPosJ); }
	}

	void defaultPos() {
		params[XYPad::X_POS_PARAM].value = displayWidth / 2.0;
		params[XYPad::Y_POS_PARAM].value = displayHeight / 2.0;
	}

	bool insideBox(float x, float y){
		return x <= maxX && x >= 0 && y <= maxY && y >=0;
	}

	void setMouseDown(bool down){
		mouseDown = down;
		params[XYPad::GATE_PARAM].value = mouseDown;
		if(mouseDown){
			if(playing){stopPlayback(true);}
			points.clear();
		} else if(autoPlayOn && !inputs[XYPad::PLAY_GATE_INPUT].active){ //no auto play if wire connected to play in
			startPlayback();
		}
	}

	void updatePos(float x, float y){
		params[XYPad::X_POS_PARAM].value = clampf(x, minX, maxX);
		params[XYPad::Y_POS_PARAM].value = clampf(y, minY, maxY);
	}

	void updateMinMax(){
		minX = totalBallSize;
		minY = totalBallSize;
		maxX = displayWidth - totalBallSize;
		maxY = displayHeight - totalBallSize;

	}

	void playback(){
		if(playing && points.size() > 0){
			params[XYPad::X_POS_PARAM].value = points[curPointIdx].x;
			params[XYPad::Y_POS_PARAM].value = points[curPointIdx].y;
			if(curPointIdx < points.size()){
				curPointIdx++;
				params[XYPad::GATE_PARAM].value = true;
			} else {
				params[XYPad::GATE_PARAM].value = false;
				curPointIdx = 0;
			}
		}
	}

	void startPlayback(){
		curPointIdx = 0;
		playing = true;
	}

	void stopPlayback(bool clearPoints){
		curPointIdx = 0;
		playing = false;
		params[XYPad::GATE_PARAM].value = false;
		if(clearPoints){ points.clear(); }
	}

};

void XYPad::step() {
	if (autoBtnTrigger.process(params[AUTO_PLAY_PARAM].value)) {
		autoPlayOn = !autoPlayOn;
		if(!autoPlayOn){ //stop when auto turned off
			stopPlayback(false);
		}
	}
	repeatLight = autoPlayOn ? 1.0 : 0.0;

	if (inputs[PLAY_GATE_INPUT].active) {
		params[AUTO_PLAY_PARAM].value = 0; //disable autoplay if wire connected to play gate
		autoPlayOn = false; //disable autoplay if wire connected to play gate

		if (inputs[PLAY_GATE_INPUT].value >= 1.0) {
			if(!playing){startPlayback();}
		} else {
			if(playing){stopPlayback(false);}
		}
	}

	bool nextStep = false;
	float clockTime = 60;
	phase += clockTime / gSampleRate;
	if (phase >= 1.0) {
		phase -= 1.0;
		nextStep = true;
	}
	if (nextStep) {
		if(playing){//continue playback
			playback();
		} else if(mouseDown){ //recording
			points.push_back(Vec(params[XYPad::X_POS_PARAM].value, params[XYPad::Y_POS_PARAM].value));
		}
	}

	float xOut = rescalef(params[X_POS_PARAM].value, minX, maxX, minVolt, maxVolt);
	float yOut = rescalef(params[Y_POS_PARAM].value, minY, maxY, maxVolt, minVolt); //y is inverted because gui coords
	outputs[X_OUTPUT].value = (xOut + params[OFFSET_X_VOLTS_PARAM].value) * params[SCALE_PARAM].value;
	outputs[Y_OUTPUT].value = (yOut + params[OFFSET_Y_VOLTS_PARAM].value) * params[SCALE_PARAM].value;

	float xInvOut = rescalef(params[X_POS_PARAM].value, minX, maxX, maxVolt, minVolt);
	float yInvOut = rescalef(params[Y_POS_PARAM].value, minY, maxY, minVolt, maxVolt); //y is inverted because gui coords
	outputs[X_INV_OUTPUT].value = (xInvOut + params[OFFSET_X_VOLTS_PARAM].value) * params[SCALE_PARAM].value;
	outputs[Y_INV_OUTPUT].value = (yInvOut + params[OFFSET_Y_VOLTS_PARAM].value) * params[SCALE_PARAM].value;

	outputs[GATE_OUTPUT].value = rescalef(params[GATE_PARAM].value, 0.0, 1.0, 0.0, 10.0);
}

struct XYPadDisplay : Widget {
	XYPad *module;
	XYPadDisplay() {}

	Widget *onMouseDown(Vec pos, int button){ module->setMouseDown(true); return this; }
	Widget *onMouseUp(Vec pos, int button){ module->setMouseDown(false); return this; }
	void onDragEnd(){ module->setMouseDown(false); }
	void onDragMove(Vec mouseRel) {
		if(module->mouseDown){
			Vec mousePos = gMousePos.minus(parent->getAbsolutePos()).minus(mouseRel).minus(box.pos);
			module->updatePos(mousePos.x, mousePos.y);
		}
	}

	void draw(NVGcontext *vg) {
		float ballX = module->params[XYPad::X_POS_PARAM].value;
		float ballY = module->params[XYPad::Y_POS_PARAM].value;
		float invBallX = module->displayWidth-ballX;
		float invBallY = module->displayHeight-ballY;

		//background
		nvgFillColor(vg, nvgRGB(20, 30, 33));
		nvgBeginPath(vg);
		nvgRect(vg, 0, 0, box.size.x, box.size.y);
		nvgFill(vg);

		//INVERTED///////////////////////////////////
		NVGcolor invertedCol = nvgRGB(20, 50, 53);

		//horizontal line
		nvgStrokeColor(vg, invertedCol);
		nvgBeginPath(vg);
		nvgMoveTo(vg, 0, invBallY);
		nvgLineTo(vg, box.size.x, invBallY);
		nvgStroke(vg);

		//vertical line
		nvgStrokeColor(vg, invertedCol);
		nvgBeginPath(vg);
		nvgMoveTo(vg, invBallX, 0);
		nvgLineTo(vg, invBallX, box.size.y);
		nvgStroke(vg);

		//inv ball
		nvgFillColor(vg, invertedCol);
		nvgStrokeColor(vg, invertedCol);
		nvgStrokeWidth(vg, 2);
		nvgBeginPath(vg);
		nvgCircle(vg, module->displayWidth-ballX, module->displayHeight-ballY, 10);
		if(module->params[XYPad::GATE_PARAM].value)nvgFill(vg);
		nvgStroke(vg);

		//MAIN///////////////////////////////////

		//horizontal line
		nvgStrokeColor(vg, nvgRGB(255, 255, 255));
		nvgBeginPath(vg);
		nvgMoveTo(vg, 0, ballY);
		nvgLineTo(vg, box.size.x, ballY);
		nvgStroke(vg);

		//vertical line
		nvgStrokeColor(vg, nvgRGB(255, 255, 255));
		nvgBeginPath(vg);
		nvgMoveTo(vg, ballX, 0);
		nvgLineTo(vg, ballX, box.size.y);
		nvgStroke(vg);

		//ball
		nvgFillColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeWidth(vg, 2);
		nvgBeginPath(vg);
		nvgCircle(vg, ballX, ballY, 10);
		if(module->params[XYPad::GATE_PARAM].value)nvgFill(vg);
		nvgStroke(vg);
	}
};

XYPadWidget::XYPadWidget() {
	XYPad *module = new XYPad();
	setModule(module);
	box.size = Vec(RACK_GRID_WIDTH*24, RACK_GRID_HEIGHT);

	{
		LightPanel *panel = new LightPanel();
		panel->box.size = box.size;
		addChild(panel);
	}

	{
		XYPadDisplay *display = new XYPadDisplay();
		display->module = module;
		display->box.pos = Vec(2, 40);
		display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 80);
		addChild(display);

		module->displayWidth = display->box.size.x;
		module->displayHeight = display->box.size.y;
		module->updateMinMax();
		module->defaultPos();
	}

	////////////////////////////////////////////////////////////
	rack::Label* const titleLabel = new rack::Label;
	titleLabel->box.pos = Vec(2, 2);
	titleLabel->text = "XY Pad";
	addChild(titleLabel);

	rack::Label* const scaleLabel = new rack::Label;
	scaleLabel->box.pos = Vec(203-20, 2);
	scaleLabel->text = "Scale";
	addChild(scaleLabel);

	rack::Label* const xOffsetLabel = new rack::Label;
	xOffsetLabel->box.pos = Vec(250-20, 2);
	xOffsetLabel->text = "X OFST";
	addChild(xOffsetLabel);

	rack::Label* const yOffsetLabel = new rack::Label;
	yOffsetLabel->box.pos = Vec(300-20, 2);
	yOffsetLabel->text = "Y OFST";
	addChild(yOffsetLabel);

	addParam(createParam<TinyBlackKnob>(Vec(200, 20), module, XYPad::SCALE_PARAM, 0.01, 1.0, 0.5));
	addParam(createParam<TinyBlackKnob>(Vec(250, 20), module, XYPad::OFFSET_X_VOLTS_PARAM, -5.0, 5.0, 5.0));
	addParam(createParam<TinyBlackKnob>(Vec(300, 20), module, XYPad::OFFSET_Y_VOLTS_PARAM, -5.0, 5.0, 5.0));

	////////////////////////////////////////////////////////////
	rack::Label* const trigLabel = new rack::Label;
	trigLabel->box.pos = Vec(2, 340);
	trigLabel->text = "Gate";
	addChild(trigLabel);

	rack::Label* const autoLabel = new rack::Label;
	autoLabel->box.pos = Vec(58-20, 340);
	autoLabel->text = "Auto";
	addChild(autoLabel);

	rack::Label* const xLabel = new rack::Label;
	xLabel->box.pos = Vec(240-4, 340);
	xLabel->text = "X";
	addChild(xLabel);

	rack::Label* const yLabel = new rack::Label;
	yLabel->box.pos = Vec(260-4, 340);
	yLabel->text = "Y";
	addChild(yLabel);

	rack::Label* const xInvLabel = new rack::Label;
	xInvLabel->box.pos = Vec(290-7, 340);
	xInvLabel->text = "-X";
	addChild(xInvLabel);

	rack::Label* const yInvLabel = new rack::Label;
	yInvLabel->box.pos = Vec(310-7, 340);
	yInvLabel->text = "-Y";
	addChild(yInvLabel);

	rack::Label* const gLabel = new rack::Label;
	gLabel->box.pos = Vec(340-5, 340);
	gLabel->text = "G";
	addChild(gLabel);

	addInput(createInput<TinyPJ301MPort>(Vec(15, 360), module, XYPad::PLAY_GATE_INPUT));

	addParam(createParam<LEDButton>(Vec(50, 358), module, XYPad::AUTO_PLAY_PARAM, 0.0, 1.0, 0.0));
	addChild(createValueLight<SmallLight<MyBlueValueLight>>(Vec(50+5, 358+5), &module->repeatLight));

	addOutput(createOutput<TinyPJ301MPort>(Vec(240, 360), module, XYPad::X_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(260, 360), module, XYPad::Y_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(290, 360), module, XYPad::X_INV_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(310, 360), module, XYPad::Y_INV_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(340, 360), module, XYPad::GATE_OUTPUT));
}

<commit_msg>better xy pad recording<commit_after>#include <string.h>
#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct XYPad : Module {
	enum ParamIds {
		X_POS_PARAM,
		Y_POS_PARAM,
		GATE_PARAM,
		OFFSET_X_VOLTS_PARAM,
		OFFSET_Y_VOLTS_PARAM,
		SCALE_PARAM,
		AUTO_PLAY_PARAM,
		NUM_PARAMS
	};
	enum InputIds {
		PLAY_GATE_INPUT,
		NUM_INPUTS
	};
	enum OutputIds {
		X_OUTPUT,
		Y_OUTPUT,
		X_INV_OUTPUT,
		Y_INV_OUTPUT,
		GATE_OUTPUT,
		NUM_OUTPUTS
	};

	float minX = 0, minY = 0, maxX = 0, maxY = 0;
	float displayWidth = 0, displayHeight = 0;
	float totalBallSize = 12;
	float minVolt = -5, maxVolt = 5;
	float repeatLight = 0.0;
	float phase = 0.0;
	bool autoPlayOn = false;
	bool playing = false;
	bool mouseDown = false;
	SchmittTrigger autoBtnTrigger;
	SchmittTrigger playbackTrigger;
	std::vector<Vec> points;
	int curPointIdx = 0;

	XYPad() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
	void step();
	void initialize(){
		defaultPos();
	}

	json_t *toJson() {
		json_t *rootJ = json_object();
		json_object_set_new(rootJ, "xPos", json_real(params[X_POS_PARAM].value));
		json_object_set_new(rootJ, "yPos", json_real(params[Y_POS_PARAM].value));
		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		json_t *xPosJ = json_object_get(rootJ, "xPos");
		json_t *yPosJ = json_object_get(rootJ, "yPos");
		if (xPosJ){ params[X_POS_PARAM].value = json_real_value(xPosJ); }
		if (yPosJ){ params[Y_POS_PARAM].value = json_real_value(yPosJ); }
	}

	void defaultPos() {
		params[XYPad::X_POS_PARAM].value = displayWidth / 2.0;
		params[XYPad::Y_POS_PARAM].value = displayHeight / 2.0;
	}

	bool insideBox(float x, float y){
		return x <= maxX && x >= 0 && y <= maxY && y >=0;
	}

	void setMouseDown(bool down){
		mouseDown = down;
		params[XYPad::GATE_PARAM].value = mouseDown;
		if(mouseDown){
			if(playing){stopPlayback(true);}
			points.clear();
			params[XYPad::GATE_PARAM].value = true; //start gate if playing and you press the mouse button down
		} else if(autoPlayOn && !inputs[XYPad::PLAY_GATE_INPUT].active){ //no auto play if wire connected to play in
			startPlayback();
		}
	}

	void updatePos(float x, float y){
		params[XYPad::X_POS_PARAM].value = clampf(x, minX, maxX);
		params[XYPad::Y_POS_PARAM].value = clampf(y, minY, maxY);
	}

	void updateMinMax(){
		minX = totalBallSize;
		minY = totalBallSize;
		maxX = displayWidth - totalBallSize;
		maxY = displayHeight - totalBallSize;

	}

	void playback(){
		if(playing && points.size() > 0){
			params[XYPad::X_POS_PARAM].value = points[curPointIdx].x;
			params[XYPad::Y_POS_PARAM].value = points[curPointIdx].y;
			if(curPointIdx < points.size()){
				curPointIdx++;
				params[XYPad::GATE_PARAM].value = true;
			} else {
				params[XYPad::GATE_PARAM].value = false;
				curPointIdx = 0;
			}
		}
	}

	void startPlayback(){
		curPointIdx = 0;
		playing = true;
	}

	void stopPlayback(bool clearPoints){
		curPointIdx = 0;
		playing = false;
		params[XYPad::GATE_PARAM].value = false;
		if(clearPoints){ points.clear(); }
	}

};

void XYPad::step() {
	if (autoBtnTrigger.process(params[AUTO_PLAY_PARAM].value)) {
		autoPlayOn = !autoPlayOn;
		if(!autoPlayOn){ //stop when auto turned off
			stopPlayback(false);
		}
	}
	repeatLight = autoPlayOn ? 1.0 : 0.0;

	if (inputs[PLAY_GATE_INPUT].active) {
		params[AUTO_PLAY_PARAM].value = 0; //disable autoplay if wire connected to play gate
		autoPlayOn = false; //disable autoplay if wire connected to play gate

		if (inputs[PLAY_GATE_INPUT].value >= 1.0) {
			if(!playing){startPlayback();}
		} else {
			if(playing){stopPlayback(false);}
		}
	}

	bool nextStep = false;
	float clockTime = 60;
	phase += clockTime / gSampleRate;
	if (phase >= 1.0) {
		phase -= 1.0;
		nextStep = true;
	}
	if (nextStep) {
		if(playing){//continue playback
			playback();
		} else if(mouseDown){ //recording
			points.push_back(Vec(params[XYPad::X_POS_PARAM].value, params[XYPad::Y_POS_PARAM].value));
		}
	}

	float xOut = rescalef(params[X_POS_PARAM].value, minX, maxX, minVolt, maxVolt);
	float yOut = rescalef(params[Y_POS_PARAM].value, minY, maxY, maxVolt, minVolt); //y is inverted because gui coords
	outputs[X_OUTPUT].value = (xOut + params[OFFSET_X_VOLTS_PARAM].value) * params[SCALE_PARAM].value;
	outputs[Y_OUTPUT].value = (yOut + params[OFFSET_Y_VOLTS_PARAM].value) * params[SCALE_PARAM].value;

	float xInvOut = rescalef(params[X_POS_PARAM].value, minX, maxX, maxVolt, minVolt);
	float yInvOut = rescalef(params[Y_POS_PARAM].value, minY, maxY, minVolt, maxVolt); //y is inverted because gui coords
	outputs[X_INV_OUTPUT].value = (xInvOut + params[OFFSET_X_VOLTS_PARAM].value) * params[SCALE_PARAM].value;
	outputs[Y_INV_OUTPUT].value = (yInvOut + params[OFFSET_Y_VOLTS_PARAM].value) * params[SCALE_PARAM].value;

	outputs[GATE_OUTPUT].value = rescalef(params[GATE_PARAM].value, 0.0, 1.0, 0.0, 10.0);
}

struct XYPadDisplay : Widget {
	XYPad *module;
	XYPadDisplay() {}

	Widget *onMouseDown(Vec pos, int button){ module->setMouseDown(true); return this; }
	Widget *onMouseUp(Vec pos, int button){ module->setMouseDown(false); return this; }
	void onDragEnd(){ module->setMouseDown(false); }
	void onDragMove(Vec mouseRel) {
		if(module->mouseDown){
			Vec mousePos = gMousePos.minus(parent->getAbsolutePos()).minus(mouseRel).minus(box.pos);
			module->updatePos(mousePos.x, mousePos.y);
		}
	}

	void draw(NVGcontext *vg) {
		float ballX = module->params[XYPad::X_POS_PARAM].value;
		float ballY = module->params[XYPad::Y_POS_PARAM].value;
		float invBallX = module->displayWidth-ballX;
		float invBallY = module->displayHeight-ballY;

		//background
		nvgFillColor(vg, nvgRGB(20, 30, 33));
		nvgBeginPath(vg);
		nvgRect(vg, 0, 0, box.size.x, box.size.y);
		nvgFill(vg);

		//INVERTED///////////////////////////////////
		NVGcolor invertedCol = nvgRGB(20, 50, 53);

		//horizontal line
		nvgStrokeColor(vg, invertedCol);
		nvgBeginPath(vg);
		nvgMoveTo(vg, 0, invBallY);
		nvgLineTo(vg, box.size.x, invBallY);
		nvgStroke(vg);

		//vertical line
		nvgStrokeColor(vg, invertedCol);
		nvgBeginPath(vg);
		nvgMoveTo(vg, invBallX, 0);
		nvgLineTo(vg, invBallX, box.size.y);
		nvgStroke(vg);

		//inv ball
		nvgFillColor(vg, invertedCol);
		nvgStrokeColor(vg, invertedCol);
		nvgStrokeWidth(vg, 2);
		nvgBeginPath(vg);
		nvgCircle(vg, module->displayWidth-ballX, module->displayHeight-ballY, 10);
		if(module->params[XYPad::GATE_PARAM].value)nvgFill(vg);
		nvgStroke(vg);

		//MAIN///////////////////////////////////

		//horizontal line
		nvgStrokeColor(vg, nvgRGB(255, 255, 255));
		nvgBeginPath(vg);
		nvgMoveTo(vg, 0, ballY);
		nvgLineTo(vg, box.size.x, ballY);
		nvgStroke(vg);

		//vertical line
		nvgStrokeColor(vg, nvgRGB(255, 255, 255));
		nvgBeginPath(vg);
		nvgMoveTo(vg, ballX, 0);
		nvgLineTo(vg, ballX, box.size.y);
		nvgStroke(vg);

		//ball
		nvgFillColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeWidth(vg, 2);
		nvgBeginPath(vg);
		nvgCircle(vg, ballX, ballY, 10);
		if(module->params[XYPad::GATE_PARAM].value)nvgFill(vg);
		nvgStroke(vg);
	}
};

XYPadWidget::XYPadWidget() {
	XYPad *module = new XYPad();
	setModule(module);
	box.size = Vec(RACK_GRID_WIDTH*24, RACK_GRID_HEIGHT);

	{
		LightPanel *panel = new LightPanel();
		panel->box.size = box.size;
		addChild(panel);
	}

	{
		XYPadDisplay *display = new XYPadDisplay();
		display->module = module;
		display->box.pos = Vec(2, 40);
		display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 80);
		addChild(display);

		module->displayWidth = display->box.size.x;
		module->displayHeight = display->box.size.y;
		module->updateMinMax();
		module->defaultPos();
	}

	////////////////////////////////////////////////////////////
	rack::Label* const titleLabel = new rack::Label;
	titleLabel->box.pos = Vec(2, 2);
	titleLabel->text = "XY Pad";
	addChild(titleLabel);

	rack::Label* const scaleLabel = new rack::Label;
	scaleLabel->box.pos = Vec(203-20, 2);
	scaleLabel->text = "Scale";
	addChild(scaleLabel);

	rack::Label* const xOffsetLabel = new rack::Label;
	xOffsetLabel->box.pos = Vec(250-20, 2);
	xOffsetLabel->text = "X OFST";
	addChild(xOffsetLabel);

	rack::Label* const yOffsetLabel = new rack::Label;
	yOffsetLabel->box.pos = Vec(300-20, 2);
	yOffsetLabel->text = "Y OFST";
	addChild(yOffsetLabel);

	addParam(createParam<TinyBlackKnob>(Vec(200, 20), module, XYPad::SCALE_PARAM, 0.01, 1.0, 0.5));
	addParam(createParam<TinyBlackKnob>(Vec(250, 20), module, XYPad::OFFSET_X_VOLTS_PARAM, -5.0, 5.0, 5.0));
	addParam(createParam<TinyBlackKnob>(Vec(300, 20), module, XYPad::OFFSET_Y_VOLTS_PARAM, -5.0, 5.0, 5.0));

	////////////////////////////////////////////////////////////
	rack::Label* const trigLabel = new rack::Label;
	trigLabel->box.pos = Vec(2, 340);
	trigLabel->text = "Gate";
	addChild(trigLabel);

	rack::Label* const autoLabel = new rack::Label;
	autoLabel->box.pos = Vec(58-20, 340);
	autoLabel->text = "Auto";
	addChild(autoLabel);

	rack::Label* const xLabel = new rack::Label;
	xLabel->box.pos = Vec(240-4, 340);
	xLabel->text = "X";
	addChild(xLabel);

	rack::Label* const yLabel = new rack::Label;
	yLabel->box.pos = Vec(260-4, 340);
	yLabel->text = "Y";
	addChild(yLabel);

	rack::Label* const xInvLabel = new rack::Label;
	xInvLabel->box.pos = Vec(290-7, 340);
	xInvLabel->text = "-X";
	addChild(xInvLabel);

	rack::Label* const yInvLabel = new rack::Label;
	yInvLabel->box.pos = Vec(310-7, 340);
	yInvLabel->text = "-Y";
	addChild(yInvLabel);

	rack::Label* const gLabel = new rack::Label;
	gLabel->box.pos = Vec(340-5, 340);
	gLabel->text = "G";
	addChild(gLabel);

	addInput(createInput<TinyPJ301MPort>(Vec(15, 360), module, XYPad::PLAY_GATE_INPUT));

	addParam(createParam<LEDButton>(Vec(50, 358), module, XYPad::AUTO_PLAY_PARAM, 0.0, 1.0, 0.0));
	addChild(createValueLight<SmallLight<MyBlueValueLight>>(Vec(50+5, 358+5), &module->repeatLight));

	addOutput(createOutput<TinyPJ301MPort>(Vec(240, 360), module, XYPad::X_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(260, 360), module, XYPad::Y_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(290, 360), module, XYPad::X_INV_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(310, 360), module, XYPad::Y_INV_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(340, 360), module, XYPad::GATE_OUTPUT));
}

<|endoftext|>


<commit_before>#include <v8.h>
#include <node.h>

#include <libtorrent/alert.hpp>

#include "alert.hpp"

using namespace v8;
using namespace node;

namespace nodelt {
  v8::Local<v8::Object> alert_to_object(const libtorrent::alert& alert) {
    HandleScope scope;
    Local<Object> obj = Object::New();

    obj->Set(String::NewSymbol("message"), String::New(alert.message().c_str()));
    obj->Set(String::NewSymbol("what"), String::New(alert.what()));
    obj->Set(String::NewSymbol("category"), Integer::New(alert.category()));
    return scope.Close(obj);
  };

  void bind_alert(Handle<Object> target) {
    Local<Object> category_t = Object::New();
    category_t->Set(String::NewSymbol("error_notification"),
      Integer::New(libtorrent::alert::error_notification));
    category_t->Set(String::NewSymbol("peer_notification"),
      Integer::New(libtorrent::alert::peer_notification));
    category_t->Set(String::NewSymbol("port_mapping_notification"),
      Integer::New(libtorrent::alert::port_mapping_notification));
    category_t->Set(String::NewSymbol("storage_notification"),
      Integer::New(libtorrent::alert::storage_notification));
    category_t->Set(String::NewSymbol("tracker_notification"),
      Integer::New(libtorrent::alert::tracker_notification));
    category_t->Set(String::NewSymbol("debug_notification"),
      Integer::New(libtorrent::alert::debug_notification));
    category_t->Set(String::NewSymbol("status_notification"),
      Integer::New(libtorrent::alert::status_notification));
    category_t->Set(String::NewSymbol("progress_notification"),
      Integer::New(libtorrent::alert::progress_notification));
    category_t->Set(String::NewSymbol("ip_block_notification"),
      Integer::New(libtorrent::alert::ip_block_notification));
    category_t->Set(String::NewSymbol("performance_warning"),
      Integer::New(libtorrent::alert::performance_warning));
    category_t->Set(String::NewSymbol("dht_notification"),
      Integer::New(libtorrent::alert::dht_notification));
    category_t->Set(String::NewSymbol("stats_notification"),
      Integer::New(libtorrent::alert::stats_notification));
    category_t->Set(String::NewSymbol("rss_notification"),
      Integer::New(libtorrent::alert::rss_notification));
    category_t->Set(String::NewSymbol("all_categories"),
      Integer::New(libtorrent::alert::all_categories));
    target->Set(String::NewSymbol("category_t"), category_t);
  };
}; // namespace nodelt
<commit_msg>alert converted to nan2<commit_after>#include <v8.h>
#include <nan.h>
#include <node.h>

#include <libtorrent/alert.hpp>

#include "alert.hpp"

using namespace v8;
using namespace node;

namespace nodelt {
    v8::Local<v8::Object> alert_to_object(const libtorrent::alert& alert) {
        Nan::EscapableHandleScope scope;
        Local<Object> obj = Nan::New<Object>();

        obj->Set(Nan::New("message").ToLocalChecked(), Nan::New(alert.message()).ToLocalChecked());
        obj->Set(Nan::New("what").ToLocalChecked(), Nan::New(alert.what()).ToLocalChecked());
        obj->Set(Nan::New("category").ToLocalChecked(), Nan::New<Integer>(alert.category()));

        return scope.Escape(obj);
    };

    void bind_alert(Local<Object> target) {
        Local<Object> category_t = Nan::New<Object>();

        category_t->Set(Nan::New("error_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::error_notification));
        category_t->Set(Nan::New("peer_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::peer_notification));
        category_t->Set(Nan::New("port_mapping_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::port_mapping_notification));
        category_t->Set(Nan::New("storage_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::storage_notification));
        category_t->Set(Nan::New("tracker_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::tracker_notification));
        category_t->Set(Nan::New("debug_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::debug_notification));
        category_t->Set(Nan::New("status_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::status_notification));
        category_t->Set(Nan::New("progress_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::progress_notification));
        category_t->Set(Nan::New("ip_block_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::ip_block_notification));
        category_t->Set(Nan::New("performance_warning").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::performance_warning));
        category_t->Set(Nan::New("dht_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::dht_notification));
        category_t->Set(Nan::New("stats_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::stats_notification));
        category_t->Set(Nan::New("rss_notification").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::rss_notification));
        category_t->Set(Nan::New("all_categories").ToLocalChecked(),
            Nan::New<Integer>(libtorrent::alert::all_categories));

        target->Set(Nan::New("category_t").ToLocalChecked(), category_t);
  };
}; // namespace nodelt
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg, Daniel Wallin
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 author 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 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 "libtorrent/pch.hpp"

#include "libtorrent/alert.hpp"
#include <boost/thread/xtime.hpp>

enum { queue_size_limit = 1000 };

namespace libtorrent {

	alert::alert() : m_timestamp(time_now()) {}
	alert::~alert() {}
	ptime alert::timestamp() const { return m_timestamp; }

	alert_manager::alert_manager()
		: m_alert_mask(alert::error_notification)
	{}

	alert_manager::~alert_manager()
	{
		while (!m_alerts.empty())
		{
			delete m_alerts.front();
			m_alerts.pop();
		}
	}

	alert const* alert_manager::wait_for_alert(time_duration max_wait)
	{
		boost::mutex::scoped_lock lock(m_mutex);

		if (!m_alerts.empty()) return m_alerts.front();

		int secs = total_seconds(max_wait);
		max_wait -= seconds(secs);
		boost::xtime xt;
		boost::xtime_get(&xt, boost::TIME_UTC);
		xt.sec += secs;
		boost::int64_t nsec = xt.nsec + total_microseconds(max_wait) * 1000;
		if (nsec > 1000000000)
		{
			nsec -= 1000000000;
			xt.sec += 1;
		}
		xt.nsec = boost::xtime::xtime_nsec_t(nsec);
		if (!m_condition.timed_wait(lock, xt)) return 0;
		TORRENT_ASSERT(!m_alerts.empty());
		if (m_alerts.empty()) return 0;
		return m_alerts.front();
	}

	void alert_manager::post_alert(const alert& alert_)
	{
		boost::mutex::scoped_lock lock(m_mutex);

		if (m_alerts.size() >= queue_size_limit) return;
		m_alerts.push(alert_.clone().release());
		m_condition.notify_all();
	}

	std::auto_ptr<alert> alert_manager::get()
	{
		boost::mutex::scoped_lock lock(m_mutex);

		TORRENT_ASSERT(!m_alerts.empty());

		alert* result = m_alerts.front();
		m_alerts.pop();
		return std::auto_ptr<alert>(result);
	}

	bool alert_manager::pending() const
	{
		boost::mutex::scoped_lock lock(m_mutex);

		return !m_alerts.empty();
	}

} // namespace libtorrent

<commit_msg>removed invalid assert<commit_after>/*

Copyright (c) 2003, Arvid Norberg, Daniel Wallin
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 author 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 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 "libtorrent/pch.hpp"

#include "libtorrent/alert.hpp"
#include <boost/thread/xtime.hpp>

enum { queue_size_limit = 1000 };

namespace libtorrent {

	alert::alert() : m_timestamp(time_now()) {}
	alert::~alert() {}
	ptime alert::timestamp() const { return m_timestamp; }

	alert_manager::alert_manager()
		: m_alert_mask(alert::error_notification)
	{}

	alert_manager::~alert_manager()
	{
		while (!m_alerts.empty())
		{
			delete m_alerts.front();
			m_alerts.pop();
		}
	}

	alert const* alert_manager::wait_for_alert(time_duration max_wait)
	{
		boost::mutex::scoped_lock lock(m_mutex);

		if (!m_alerts.empty()) return m_alerts.front();

		int secs = total_seconds(max_wait);
		max_wait -= seconds(secs);
		boost::xtime xt;
		boost::xtime_get(&xt, boost::TIME_UTC);
		xt.sec += secs;
		boost::int64_t nsec = xt.nsec + total_microseconds(max_wait) * 1000;
		if (nsec > 1000000000)
		{
			nsec -= 1000000000;
			xt.sec += 1;
		}
		xt.nsec = boost::xtime::xtime_nsec_t(nsec);
		// apparently this call can be interrupted
		// prematurely if there are other signals
		if (!m_condition.timed_wait(lock, xt)) return 0;
		if (m_alerts.empty()) return 0;
		return m_alerts.front();
	}

	void alert_manager::post_alert(const alert& alert_)
	{
		boost::mutex::scoped_lock lock(m_mutex);

		if (m_alerts.size() >= queue_size_limit) return;
		m_alerts.push(alert_.clone().release());
		m_condition.notify_all();
	}

	std::auto_ptr<alert> alert_manager::get()
	{
		boost::mutex::scoped_lock lock(m_mutex);

		TORRENT_ASSERT(!m_alerts.empty());

		alert* result = m_alerts.front();
		m_alerts.pop();
		return std::auto_ptr<alert>(result);
	}

	bool alert_manager::pending() const
	{
		boost::mutex::scoped_lock lock(m_mutex);

		return !m_alerts.empty();
	}

} // namespace libtorrent

<|endoftext|>