<commit_before>#include "libnanocv/nanocv.h"
#include "libnanocv/tabulator.h"
#include "libnanocv/util/measure.hpp"
#include "libnanocv/thread/thread.h"
#include "libnanocv/trainers/batch.h"
#include "libnanocv/trainers/minibatch.h"
#include "libnanocv/trainers/stochastic.h"
#include "libnanocv/tasks/task_synthetic_shapes.h"

using namespace ncv;

static string_t stats_to_string(const stats_t<scalar_t>& stats)
{
        return  text::to_string(stats.avg())
                + " [" + text::to_string(stats.min()) + ", " + text::to_string(stats.max()) + "]";
}

template
<
        typename ttrainer
>
static void test_optimizer(model_t& model, ttrainer trainer, const string_t& name, tabulator_t& table)
{
        const size_t cmd_trials = 16;

        stats_t<scalar_t> tvalues;
        stats_t<scalar_t> vvalues;
        stats_t<scalar_t> terrors;
        stats_t<scalar_t> verrors;

        log_info() << "<<< running " << name << " ...";

        const size_t usec = ncv::measure_robustly_usec([&] ()
        {
                model.random_params();

                const trainer_result_t result = trainer();

                tvalues(result.m_opt_state.m_tvalue);
                vvalues(result.m_opt_state.m_vvalue);

                terrors(result.m_opt_state.m_terror_avg);
                verrors(result.m_opt_state.m_verror_avg);
        }, cmd_trials);

        table.append(name)
                << stats_to_string(tvalues) << stats_to_string(terrors)
                << stats_to_string(vvalues) << stats_to_string(verrors)
                << (usec / 1000);
}

static void test_optimizers(
        const task_t& task, model_t& model, const sampler_t& tsampler, const sampler_t& vsampler,
        const loss_t& loss, const string_t& criterion)
{
        const size_t cmd_iterations = 128;
        const size_t cmd_epochs = cmd_iterations;
        const scalar_t cmd_epsilon = 1e-4;
        const bool verbose = false;

        // batch optimizers
        const auto batch_optimizers =
        {
                batch_optimizer::GD,
                batch_optimizer::CGD,
                batch_optimizer::LBFGS
        };

        // minibatch optimizers
        const auto minibatch_optimizers =
        {
                batch_optimizer::GD,
                batch_optimizer::CGD,
                batch_optimizer::LBFGS
        };

        // stochastic optimizers
        const auto stochastic_optimizers =
        {
                stochastic_optimizer::SG,
                stochastic_optimizer::SGA,
                stochastic_optimizer::SIA,
                stochastic_optimizer::AG,
                stochastic_optimizer::ADAGRAD,
                stochastic_optimizer::ADADELTA
        };

        // run optimizers and collect results
        tabulator_t table("optimizer\\");
        table.header() << "train loss" << "train error" << "valid loss" << "valid error" << "time [msec]";

        for (batch_optimizer optimizer : batch_optimizers)
        {
                test_optimizer(model, [&] ()
                {
                        return ncv::batch_train(
                                model, task, tsampler, vsampler, ncv::n_threads(),
                                loss, criterion, optimizer, cmd_iterations, cmd_epsilon, verbose);
                }, "batch [" + text::to_string(optimizer) + "]", table);
        }

//        for (batch_optimizer optimizer : minibatch_optimizers)
//        {
//                test_optimizer(model, [&] ()
//                {
//                        return ncv::minibatch_train(
//                                model, task, tsampler, vsampler, ncv::n_threads(),
//                                loss, criterion, optimizer, cmd_epochs, cmd_epsilon, verbose);
//                }, "minibatch [" + text::to_string(optimizer) + "]", table);
//        }

//        for (stochastic_optimizer optimizer : stochastic_optimizers)
//        {
//                test_optimizer(model, [&] ()
//                {
//                        return ncv::stochastic_train(
//                                model, task, tsampler, vsampler, ncv::n_threads(),
//                                loss, criterion, optimizer, cmd_epochs, verbose);
//                }, "stochastic [" + text::to_string(optimizer) + "]", table);
//        }

        table.print(std::cout);
}

int main(int argc, char *argv[])
{
        ncv::init();

        const size_t cmd_samples = 8 * 1024;
        const size_t cmd_rows = 16;
        const size_t cmd_cols = 16;
        const size_t cmd_outputs = 10;
        const color_mode cmd_color = color_mode::rgba;

        // create task
        synthetic_shapes_task_t task(
                "rows=" + text::to_string(cmd_rows) + "," +
                "cols=" + text::to_string(cmd_cols) + "," +
                "color=" + text::to_string(cmd_color) + "," +
                "dims=" + text::to_string(cmd_outputs) + "," +
                "size=" + text::to_string(cmd_samples));
        task.load("");
	task.describe();

        // create training & validation samples
        sampler_t tsampler(task);
        tsampler.setup(sampler_t::atype::annotated);

        sampler_t vsampler(task);
        tsampler.split(80, vsampler);

        // construct models
        const string_t lmodel0;
        const string_t lmodel1 = lmodel0 + "linear:dims=16;act-snorm;";
        const string_t lmodel2 = lmodel1 + "linear:dims=16;act-snorm;";
        const string_t lmodel3 = lmodel2 + "linear:dims=16;act-snorm;";

        string_t cmodel;
        cmodel = cmodel + "conv:dims=8,rows=5,cols=5;pool-max;act-snorm;";
        cmodel = cmodel + "conv:dims=8,rows=3,cols=3;act-snorm;";

        const string_t outlayer = "linear:dims=" + text::to_string(cmd_outputs) + ";";

        strings_t cmd_networks =
        {
                lmodel0 + outlayer,
//                lmodel1 + outlayer,
//                lmodel2 + outlayer,
//                lmodel3 + outlayer,

//                cmodel + outlayer
        };

        const strings_t cmd_losses = { "classnll" }; //logistic" }; //"classnll", //loss_manager_t::instance().ids();
        const strings_t cmd_criteria = { "avg" }; //criterion_manager_t::instance().ids();

        // vary the model
        for (const string_t& cmd_network : cmd_networks)
        {
                log_info() << "<<< running network [" << cmd_network << "] ...";

                const rmodel_t model = model_manager_t::instance().get("forward-network", cmd_network);
                assert(model);
                model->resize(task, true);

                // vary the loss
                for (const string_t& cmd_loss : cmd_losses)
                {
                        log_info() << "<<< running loss [" << cmd_loss << "] ...";

                        const rloss_t loss = loss_manager_t::instance().get(cmd_loss);
                        assert(loss);

                        // vary the criteria
                        for (const string_t& cmd_criterion : cmd_criteria)
                        {
                                log_info() << "<<< running criterion [" << cmd_criterion << "] ...";

                                test_optimizers(task, *model, tsampler, vsampler, *loss, cmd_criterion);
                        }
                }

                log_info();
        }

        // OK
        log_info() << done;
        return EXIT_SUCCESS;
}
<commit_msg>update benchmark program<commit_after>#include "libnanocv/nanocv.h"
#include "libnanocv/tabulator.h"
#include "libnanocv/util/measure.hpp"
#include "libnanocv/thread/thread.h"
#include "libnanocv/trainers/batch.h"
#include "libnanocv/trainers/minibatch.h"
#include "libnanocv/trainers/stochastic.h"
#include "libnanocv/tasks/task_synthetic_shapes.h"

using namespace ncv;

static string_t stats_to_string(const stats_t<scalar_t>& stats)
{
        return  text::to_string(stats.avg())
                + " [" + text::to_string(stats.min())
                + ", " + text::to_string(stats.max())
                + "]";
}

template
<
        typename ttrainer
>
static void test_optimizer(model_t& model, ttrainer trainer, const string_t& name, tabulator_t& table)
{
        const size_t cmd_trials = 16;

        stats_t<scalar_t> tvalues;
        stats_t<scalar_t> vvalues;
        stats_t<scalar_t> terrors;
        stats_t<scalar_t> verrors;

        log_info() << "<<< running " << name << " ...";

        const size_t usec = ncv::measure_robustly_usec([&] ()
        {
                model.random_params();

                const trainer_result_t result = trainer();

                tvalues(result.m_opt_state.m_tvalue);
                vvalues(result.m_opt_state.m_vvalue);

                terrors(result.m_opt_state.m_terror_avg);
                verrors(result.m_opt_state.m_verror_avg);
        }, cmd_trials);

        table.append(name)
                << stats_to_string(tvalues) << stats_to_string(terrors)
                << stats_to_string(vvalues) << stats_to_string(verrors)
                << (usec / 1000);
}

static void test_optimizers(
        const task_t& task, model_t& model, const sampler_t& tsampler, const sampler_t& vsampler,
        const loss_t& loss, const string_t& criterion)
{
        const size_t cmd_iterations = 64;
        const size_t cmd_minibatch_epochs = cmd_iterations / 8;         // NB: because of 8 iterations / batch!
        const size_t cmd_stochastic_epochs = cmd_iterations;
        const scalar_t cmd_epsilon = 1e-4;
        const bool verbose = false;

        // batch optimizers
        const auto batch_optimizers =
        {
                batch_optimizer::GD,
                batch_optimizer::CGD,
                batch_optimizer::LBFGS
        };

        // minibatch optimizers
        const auto minibatch_optimizers =
        {
                batch_optimizer::GD,
                batch_optimizer::CGD,
                batch_optimizer::LBFGS
        };

        // stochastic optimizers
        const auto stochastic_optimizers =
        {
                stochastic_optimizer::SG,
                stochastic_optimizer::SGA,
                stochastic_optimizer::SIA,
                stochastic_optimizer::AG,
                stochastic_optimizer::ADAGRAD,
                stochastic_optimizer::ADADELTA
        };

        // run optimizers and collect results
        tabulator_t table("optimizer\\");
        table.header() << "train loss" << "train error" << "valid loss" << "valid error" << "time [msec]";

        for (batch_optimizer optimizer : batch_optimizers)
        {
                test_optimizer(model, [&] ()
                {
                        return ncv::batch_train(
                                model, task, tsampler, vsampler, ncv::n_threads(),
                                loss, criterion, optimizer, cmd_iterations, cmd_epsilon, verbose);
                }, "batch [" + text::to_string(optimizer) + "]", table);
        }

        for (batch_optimizer optimizer : minibatch_optimizers)
        {
                test_optimizer(model, [&] ()
                {
                        return ncv::minibatch_train(
                                model, task, tsampler, vsampler, ncv::n_threads(),
                                loss, criterion, optimizer, cmd_minibatch_epochs, cmd_epsilon, verbose);
                }, "minibatch [" + text::to_string(optimizer) + "]", table);
        }

        for (stochastic_optimizer optimizer : stochastic_optimizers)
        {
                test_optimizer(model, [&] ()
                {
                        return ncv::stochastic_train(
                                model, task, tsampler, vsampler, ncv::n_threads(),
                                loss, criterion, optimizer, cmd_stochastic_epochs, verbose);
                }, "stochastic [" + text::to_string(optimizer) + "]", table);
        }

        table.print(std::cout);
}

int main(int argc, char *argv[])
{
        ncv::init();

        const size_t cmd_samples = 8 * 1024;
        const size_t cmd_rows = 16;
        const size_t cmd_cols = 16;
        const size_t cmd_outputs = 10;
        const color_mode cmd_color = color_mode::luma;

        // create task
        synthetic_shapes_task_t task(
                "rows=" + text::to_string(cmd_rows) + "," +
                "cols=" + text::to_string(cmd_cols) + "," +
                "color=" + text::to_string(cmd_color) + "," +
                "dims=" + text::to_string(cmd_outputs) + "," +
                "size=" + text::to_string(cmd_samples));
        task.load("");
	task.describe();

        // create training & validation samples
        sampler_t tsampler(task);
        tsampler.setup(sampler_t::atype::annotated);

        sampler_t vsampler(task);
        tsampler.split(80, vsampler);

        // construct models
        const string_t lmodel0;
        const string_t lmodel1 = lmodel0 + "linear:dims=16;act-snorm;";
        const string_t lmodel2 = lmodel1 + "linear:dims=16;act-snorm;";
        const string_t lmodel3 = lmodel2 + "linear:dims=16;act-snorm;";

        string_t cmodel;
        cmodel = cmodel + "conv:dims=8,rows=5,cols=5;pool-max;act-snorm;";
        cmodel = cmodel + "conv:dims=8,rows=3,cols=3;act-snorm;";

        const string_t outlayer = "linear:dims=" + text::to_string(cmd_outputs) + ";";

        strings_t cmd_networks =
        {
                lmodel0 + outlayer,
                lmodel1 + outlayer,
                lmodel2 + outlayer,
                lmodel3 + outlayer,

                cmodel + outlayer
        };

        const strings_t cmd_losses = { "classnll" }; //logistic" }; //"classnll", //loss_manager_t::instance().ids();
        const strings_t cmd_criteria = { "avg" }; //criterion_manager_t::instance().ids();

        // vary the model
        for (const string_t& cmd_network : cmd_networks)
        {
                log_info() << "<<< running network [" << cmd_network << "] ...";

                const rmodel_t model = model_manager_t::instance().get("forward-network", cmd_network);
                assert(model);
                model->resize(task, true);

                // vary the loss
                for (const string_t& cmd_loss : cmd_losses)
                {
                        log_info() << "<<< running loss [" << cmd_loss << "] ...";

                        const rloss_t loss = loss_manager_t::instance().get(cmd_loss);
                        assert(loss);

                        // vary the criteria
                        for (const string_t& cmd_criterion : cmd_criteria)
                        {
                                log_info() << "<<< running criterion [" << cmd_criterion << "] ...";

                                test_optimizers(task, *model, tsampler, vsampler, *loss, cmd_criterion);
                        }
                }

                log_info();
        }

        // OK
        log_info() << done;
        return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>//
//  ex13_17.cpp
//  Exercise 13.17
//
//  Created by pezy on 1/15/15.
//  Refactoed by acgtyrant Aug 2015
//
//  Write versions of numbered and f corresponding to the previous three exercises
//  and check whether you correctly predicted the output.
//
//  For 13.15

#include <iostream>

class numbered {
public:
    numbered() {
        mysn = unique++;
    }

    numbered(const numbered& n) {
        mysn = unique++;
    }

    int mysn;
    static int unique;
};

static int unique = 10;

void f(numbered s) {
    std::cout << s.mysn << std::endl;
}

int main()
{
    numbered a, b = a, c = b;
    f(a);
    f(b);
    f(c);
}
<commit_msg>fix the problem of initialize static class variable<commit_after>//
//  ex13_17.cpp
//  Exercise 13.17
//
//  Created by pezy on 1/15/15.
//  Refactoed by acgtyrant Aug 2015
//
//  Write versions of numbered and f corresponding to the previous three exercises
//  and check whether you correctly predicted the output.
//
//  For 13.15

#include <iostream>

class numbered {
public:
    numbered() {
        mysn = unique++;
    }

    numbered(const numbered& n) {
        mysn = unique++;
    }

    int mysn;
    static int unique;
};

int numbered::unique = 10;

void f(numbered s) {
    std::cout << s.mysn << std::endl;
}

int main()
{
    numbered a, b = a, c = b;
    f(a);
    f(b);
    f(c);
}
<|endoftext|>


<commit_before>/*
	TUIO Server Component - part of the reacTIVision project
	http://reactivision.sourceforge.net/

	Copyright (c) 2005-2009 Martin Kaltenbrunner <mkalten@iua.upf.edu>

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "NosuchUtil.h"
#include "TuioServer.h"

using namespace TUIO;

TuioServer::TuioServer() {
	verbose = 0;
	initial_session_id = 10000;
	device_multiplier = 1000;
}

TuioServer::~TuioServer() {
}

void
TuioServer::adjustXY(float& x, float& y) {
	if (flipY) {
		y = 1.0f - y;
	}
	if (flipX) {
		x = 1.0f - x;
	}
}
TuioCursor* TuioServer::addTuioCursor(float x, float y) {
	sessionID++;

	adjustXY(x, y);

	if (verbose) {
		printf("Added Cursor sid=%d x=%.4f y=%.4f\n", sessionID,x,y);
	}

	int cursorID = (int)cursorList.size();
	if (((int)(cursorList.size())<=maxCursorID) && ((int)(freeCursorList.size())>0)) {
		std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();

		for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
			if((*iter)->getDistance(x,y)<(*closestCursor)->getDistance(x,y)) closestCursor = iter;
		}

		TuioCursor *freeCursor = (*closestCursor);
		cursorID = (*closestCursor)->getCursorID();
		freeCursorList.erase(closestCursor);
		delete freeCursor;
	} else maxCursorID = cursorID;

	TuioCursor *tcur = new TuioCursor(sessionID, cursorID, x, y);
	cursorList.push_back(tcur);
	updateCursor = true;

	if (verbose > 2)
		std::cout << "add cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl;

	return tcur;
}

TuioCursor* TuioServer::addTuioCursorId(float x, float y, int uid, int id) {

	adjustXY(x, y);

	if (verbose) {
		printf("Added Cursor uid=%d id=%d x=%.4f y=%.4f\n", uid, id,x,y);
	}

	sessionID = uid;
	int cursorID = id;
/*
	if (((int)(cursorList.size())<=maxCursorID) && ((int)(freeCursorList.size())>0)) {
		std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();

		for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
			if((*iter)->getDistance(x,y)<(*closestCursor)->getDistance(x,y)) closestCursor = iter;
		}

		TuioCursor *freeCursor = (*closestCursor);
		cursorID = (*closestCursor)->getCursorID();
		freeCursorList.erase(closestCursor);
		delete freeCursor;
	} else maxCursorID = cursorID;
*/

	TuioCursor *tcur = new TuioCursor(sessionID, cursorID, x, y);
	cursorList.push_back(tcur);
	updateCursor = true;

	if (verbose > 2)
		std::cout << "add cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl;

	return tcur;
}

void TuioServer::updateTuioCursor(TuioCursor *tcur,float x, float y) {
	if (tcur==NULL) return;
	adjustXY(x, y);
	tcur->update(x,y);
	updateCursor = true;

	if (verbose > 2 && tcur->isMoving())
		std::cout << "set cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY()
		<< " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl;
}

void TuioServer::removeTuioCursor(TuioCursor *tcur) {
	if (tcur==NULL) return;
	cursorList.remove(tcur);
	tcur->remove();
	updateCursor = true;

	if (verbose > 2)
		std::cout << "del cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ")" << std::endl;

	if (tcur->getCursorID()==maxCursorID) {
		maxCursorID = -1;
		delete tcur;

		if (cursorList.size()>0) {
			std::list<TuioCursor*>::iterator clist;
			for (clist=cursorList.begin(); clist != cursorList.end(); clist++) {
				int cursorID = (*clist)->getCursorID();
				if (cursorID>maxCursorID) maxCursorID=cursorID;
			}

			freeCursorBuffer.clear();
			for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
				TuioCursor *freeCursor = (*flist);
				if (freeCursor->getCursorID()>maxCursorID) delete freeCursor;
				else freeCursorBuffer.push_back(freeCursor);
			}
			freeCursorList = freeCursorBuffer;

		} else {
			for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
				TuioCursor *freeCursor = (*flist);
				delete freeCursor;
			}
			freeCursorList.clear();
		}
	} else if (tcur->getCursorID()<maxCursorID) {
		freeCursorList.push_back(tcur);
	}
}

long TuioServer::getSessionID() {
	sessionID++;
	return sessionID;
}

TuioCursor* TuioServer::getClosestTuioCursor(float xp, float yp) {

	TuioCursor *closestCursor = NULL;
	float closestDistance = 1.0f;

	for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
		float distance = (*iter)->getDistance(xp,yp);
		if(distance<closestDistance) {
			closestCursor = (*iter);
			closestDistance = distance;
		}
	}

	return closestCursor;
}

std::list<TuioCursor*> TuioServer::getTuioCursors() {
	return cursorList;
}
<commit_msg>More cleanup<commit_after>/*
	TUIO Server Component - part of the reacTIVision project
	http://reactivision.sourceforge.net/

	Copyright (c) 2005-2009 Martin Kaltenbrunner <mkalten@iua.upf.edu>

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "NosuchUtil.h"
#include "TuioServer.h"

using namespace TUIO;

TuioServer::TuioServer() {
	verbose = 0;
	initial_session_id = 10000;
	device_multiplier = 1000;
}

TuioServer::~TuioServer() {
}

void
TuioServer::adjustXY(float& x, float& y) {
	if (flipY) {
		y = 1.0f - y;
	}
	if (flipX) {
		x = 1.0f - x;
	}
}
TuioCursor* TuioServer::addTuioCursor(float x, float y) {
	sessionID++;

	adjustXY(x, y);

	int cursorID = (int)cursorList.size();
	if (((int)(cursorList.size())<=maxCursorID) && ((int)(freeCursorList.size())>0)) {
		std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();

		for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
			if((*iter)->getDistance(x,y)<(*closestCursor)->getDistance(x,y)) closestCursor = iter;
		}

		TuioCursor *freeCursor = (*closestCursor);
		cursorID = (*closestCursor)->getCursorID();
		freeCursorList.erase(closestCursor);
		delete freeCursor;
	} else maxCursorID = cursorID;

	TuioCursor *tcur = new TuioCursor(sessionID, cursorID, x, y);
	cursorList.push_back(tcur);
	updateCursor = true;

	if (verbose > 2)
		std::cout << "add cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl;

	return tcur;
}

TuioCursor* TuioServer::addTuioCursorId(float x, float y, int uid, int id) {

	adjustXY(x, y);

	sessionID = uid;
	int cursorID = id;

	TuioCursor *tcur = new TuioCursor(sessionID, cursorID, x, y);
	cursorList.push_back(tcur);
	updateCursor = true;

	if (verbose > 2)
		std::cout << "add cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl;

	return tcur;
}

void TuioServer::updateTuioCursor(TuioCursor *tcur,float x, float y) {
	if (tcur==NULL) return;
	adjustXY(x, y);
	tcur->update(x,y);
	updateCursor = true;

	if (verbose > 2 && tcur->isMoving())
		std::cout << "set cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY()
		<< " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl;
}

void TuioServer::removeTuioCursor(TuioCursor *tcur) {
	if (tcur==NULL) return;
	cursorList.remove(tcur);
	tcur->remove();
	updateCursor = true;

	if (verbose > 2)
		std::cout << "del cur " << tcur->getCursorID() << " (" <<  tcur->getSessionID() << ")" << std::endl;

	if (tcur->getCursorID()==maxCursorID) {
		maxCursorID = -1;
		delete tcur;

		if (cursorList.size()>0) {
			std::list<TuioCursor*>::iterator clist;
			for (clist=cursorList.begin(); clist != cursorList.end(); clist++) {
				int cursorID = (*clist)->getCursorID();
				if (cursorID>maxCursorID) maxCursorID=cursorID;
			}

			freeCursorBuffer.clear();
			for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
				TuioCursor *freeCursor = (*flist);
				if (freeCursor->getCursorID()>maxCursorID) delete freeCursor;
				else freeCursorBuffer.push_back(freeCursor);
			}
			freeCursorList = freeCursorBuffer;

		} else {
			for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
				TuioCursor *freeCursor = (*flist);
				delete freeCursor;
			}
			freeCursorList.clear();
		}
	} else if (tcur->getCursorID()<maxCursorID) {
		freeCursorList.push_back(tcur);
	}
}

long TuioServer::getSessionID() {
	sessionID++;
	return sessionID;
}

TuioCursor* TuioServer::getClosestTuioCursor(float xp, float yp) {

	TuioCursor *closestCursor = NULL;
	float closestDistance = 1.0f;

	for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
		float distance = (*iter)->getDistance(xp,yp);
		if(distance<closestDistance) {
			closestCursor = (*iter);
			closestDistance = distance;
		}
	}

	return closestCursor;
}

std::list<TuioCursor*> TuioServer::getTuioCursors() {
	return cursorList;
}
<|endoftext|>


<commit_before>//
//  Target.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 18/03/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#ifndef Analyser_Static_ZXSpectrum_Target_h
#define Analyser_Static_ZXSpectrum_Target_h

#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"

namespace Analyser {
namespace Static {
namespace ZXSpectrum {

struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl<Target> {
	ReflectableEnum(Model,
		SixteenK,
		FortyEightK,
		OneTwoEightK,
		Plus2,
		Plus2a,
		Plus3,
	);

	Model model = Model::Plus2a;
	bool should_hold_enter = false;

	Target(): Analyser::Static::Target(Machine::ZXSpectrum) {
		if(needs_declare()) {
			DeclareField(model);
			AnnounceEnum(Model);
		}
	}
};

}
}
}

#endif /* Target_h */
<commit_msg>Regresses default to the more-compatible +2.<commit_after>//
//  Target.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 18/03/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#ifndef Analyser_Static_ZXSpectrum_Target_h
#define Analyser_Static_ZXSpectrum_Target_h

#include "../../../Reflection/Enum.hpp"
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"

namespace Analyser {
namespace Static {
namespace ZXSpectrum {

struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl<Target> {
	ReflectableEnum(Model,
		SixteenK,
		FortyEightK,
		OneTwoEightK,
		Plus2,
		Plus2a,
		Plus3,
	);

	Model model = Model::Plus2;
	bool should_hold_enter = false;

	Target(): Analyser::Static::Target(Machine::ZXSpectrum) {
		if(needs_declare()) {
			DeclareField(model);
			AnnounceEnum(Model);
		}
	}
};

}
}
}

#endif /* Target_h */
<|endoftext|>


<commit_before>/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 PodSensor.cpp
 Copyright (c) 2016 Automatic Orchestra

 See the COPYRIGHT file at the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/COPYRIGHT.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 This file is part of Automatic Orchestra. It is subject to the license terms
 in the LICENSE file found in the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/LICENSE.

 No part of Automatic Orchestra, including this file, may be copied, modified,
 propagated, or distributed except according to the terms contained in the
 LICENSE file.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/

#include "PodSensor.h"
#include "MotorProxy.h"
#include "CFOSynthesizer.h"
#include "MotorMessages.h"
#include "SensorMessages.h"

#define SP_DEBUG true
#define CHANNEL_DELAY_INCREMENT 15

PodSensor::PodSensor(Orchestra* pParent) : Pod(pParent) {
  // retrieve MIDI channel
  midiChannel = getParent()->getChannel();
  // calculate delay in pulses
  mPulseDelay = midiChannel * CHANNEL_DELAY_INCREMENT;
  // check if is the first Meister (lookup table,)
  if (midiChannel == meisterOrder[0])
  {
    pIsMeister = true;
  }
  else
  {
    pIsMeister = false;
  }
  // apply jakob's magic crescendo preset
  uint8_t presetArray[] = {
    23, 0, 0, 0, 50, 1, 127, 0, 121, 3, 0, 64, 64, 127, 9, 40, 0, 2, 0, 0, 0, 64, 63, 127, 4, 0, 0, 0, 0, 0, 0, 64, 61, 127, 4, 12, 0, 1, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 127, 127, 127, 127, 0, 0, 0, 0, 0, 1, 127, 127, 0, 127
  };
  applyPresets(presetArray);
#if SP_DEBUG
  Serial.printf("(PS) -> constructor(): midi channel is:  %i - meister flag: %i - pulse delay is: %i\n", midiChannel, pIsMeister, mPulseDelay);
#endif
}

PodSensor::~PodSensor() {
}

SensorOrchestra* PodSensor::getConcreteParent() {
  // upcast from base class Orchestra to concrete class SensorOrchestra
  // to gain access to motor and sensor proxy instances.
  // http://www.cplusplus.com/doc/tutorial/typecasting/
  return static_cast<SensorOrchestra*>(getParent());
}

void PodSensor::onClockBeatChange(unsigned long beat) {
  // check initial pulse at zero...
#if SP_DEBUG
  if(!getConcreteParent()->getMotor()->isActive()) {
    #if SP_DEBUG
    Serial.printf("(PS) -> onClockBeatChange(): pulse count is: %i\n", mPulseCount);
    #endif
  }
#endif
  // start motor movement after delay has elapsed
  MotorProxy* motor = getConcreteParent()->getMotor();
  if(mPulseCount >= mPulseDelay && !motor->isActive()) {
    // start acceleration phase
    motor->accelerateToSpeed(1600, 50, 1.25);
    motor->start();
  }

  //Introduction to Development Transition Check

  if (mPulseCount == pulseTimings[0])
  {

    //Update Current Tuning Tone and Meister Flag
    currentTuning = 0;
    if (midiChannel != meisterOrder[currentTuning])
    {
      pIsMeister = false;
    }
    else
    {
      pIsMeister = true;
    }

    if (!pIsMeister)
    {
      #if SP_DEBUG
        Serial.printf("(PS) -> onClockBeatChange(): currentTuning: %i ", currentTuning);
        Serial.println();
      #endif
        pGoToNote();
    }
    else
    {
      //Hold the note

    }
  }

  // ---------------------------------------
  //  play the note based on motor position
  // ---------------------------------------
  // calculate relative postion of values in buffer
  unsigned long pos = getConcreteParent()->getMotor()->mMotor.currentPosition();
  unsigned long firstBufferPos = pPositions[0];
  unsigned long relativePos = firstBufferPos + ((pos - firstBufferPos) % MotorProxy::FULL_REVOLUTION);
  // find matching index of position in buffer
  int index = -1;
  for(int i = 0; i < BUFFER_SIZE; i++) {
    // following index
    int j = (i + 1 == BUFFER_SIZE) ? 0 : i + 1;
    // check buffer values to determine index
    if(relativePos >= pPositions[i] && relativePos < pPositions[j]) {
      index = i;
      break;
    }
  }
  // play note from buffer
  if(index != -1) {
    uint16_t note = pNotes[index];
    if(note != mLastNote) {
      // finally play the new note
      Serial.printf("(PS) -> onClockBeatChange(): Note %i\n",note);
      Music.noteOn(note, 127);
      mLastNote = note;
    }
  } else {
#if SP_DEBUG
    Serial.println("(PS) -> onClockBeatChange(): No matching index found - which shouldn't happen :(");
#endif
  }

  //Development part

    if (mPulseCount >= pulseTimings[0] && mPulseCount <= pulseTimings[1])
    {
      #if SP_DEBUG
      if (currentTuning < 1)
      {
        Serial.println();
        Serial.println("(PS) -> onClockBeatChange(): change Tuning to 1");
        Serial.println();
      }
      #endif
      currentTuning = 1;
    }

    if (mPulseCount >= pulseTimings[1] && mPulseCount <= pulseTimings[2])
    {
      #if SP_DEBUG
      if (currentTuning < 2)
      {
        Serial.println();
        Serial.println("(PS) -> onClockBeatChange(): change Tuning to 2");
        Serial.println();
      }
      #endif
      currentTuning = 2;
    }

    if (mPulseCount >= pulseTimings[2] && mPulseCount <= pulseTimings[3])
    {
      #if SP_DEBUG
      if (currentTuning < 3)
      {
        Serial.println();
        Serial.println("(PS) -> onClockBeatChange(): change Tuning to 3");
        Serial.println();
      }
      #endif
      currentTuning = 3;
    }

    if (mPulseCount >= pulseTimings[3] && mPulseCount <= pulseTimings[4])
    {
      #if SP_DEBUG
      if (currentTuning < 4)
      {
        Serial.println();
        Serial.println("(PS) -> onClockBeatChange(): change Tuning to 4");
        Serial.println();
      }
      #endif
      currentTuning = 4;
    }

    if (mPulseCount >= pulseTimings[4] && mPulseCount <= pulseTimings[5])
    {
      #if SP_DEBUG
      if (currentTuning < 5)
      {
        Serial.println();
        Serial.println("(PS) -> onClockBeatChange(): change Tuning to 5");
        Serial.println();
      }
      #endif
      currentTuning = 5;
    }

    //Final Part

    if (mPulseCount >= pulseTimings[5])
    {
      #if SP_DEBUG
      if (currentTuning < 6)
      {
        Serial.println();
        Serial.println("(PS) -> onClockBeatChange(): change Tuning to 6");
        Serial.println();
      }
      #endif
      currentTuning = 6;
    }

    if (midiChannel != meisterOrder[currentTuning])
    {
      pIsMeister = false;
    }
    else
    {
      pIsMeister = true;
    }

  // therefore increment afterwards
  mPulseCount++;
}

void PodSensor::pGoToNote()
{
  #if SP_DEBUG
  Serial.println("(PS) -> onMotorMessage(): Go to Current Note");
  #endif
  //Search for Note
  // updateRealPosition();
  updateNoteToFollowIndex();
  getConcreteParent()->getMotor()->moveToPosition(
    getConcreteParent()->getMotor()->relativeToAbsolutePosition(pPositions[pNoteToFollowIndex]),
    accelPattern[currentTuning],
    maxSpeedPattern[currentTuning]
  );
}

void PodSensor::pGoToLastNote()
{
  #if SP_DEBUG
  Serial.println("(PS) -> onMotorMessage(): Go to the Last Note");
  #endif
  //Search for Note
  // updateRealPosition();
  updateNoteToFollowIndex();
  getConcreteParent()->getMotor()->moveToPosition(
    getConcreteParent()->getMotor()->relativeToAbsolutePosition(pPositions[pNoteToFollowIndex] + MotorProxy::FULL_REVOLUTION * 3),
    accelPattern[currentTuning],
    maxSpeedPattern[currentTuning]
  );
  lastDrone = true;
}

void PodSensor::onMotorMessage(uint8_t pMessage, uint16_t pValue) {
#if SP_DEBUG
  Serial.printf("(PS) -> onMotorMessage(): message: %i - value: %i\n", pMessage, pValue);
#endif
  switch(pMessage) {
    case MotorMessages::ACCELERATION_DONE:
      // start buffering phase
      getConcreteParent()->getSensor()->startBuffering();
      break;

      case MotorMessages::TURNS_DONE:
        if (pIsMeister)
        {
          #if SP_DEBUG
          Serial.println("(PS) -> onMotorMessage(): Decelerating Meister");
          #endif
          getConcreteParent()->getMotor()->decelerateToSpeed(50, 0.9);
        }
      break;

      case MotorMessages::DECELERATION_DONE:
        if (pIsMeister)
        {
          // updateRealPosition();
          updateMeisterNoteIndex();
        }
        else
        {
          #if SP_DEBUG
          Serial.println("(PS) -> onMotorMessage(): Waiting for pulse ");
          #endif
        }
      break;

      case MotorMessages::TUNING_DONE:

        if (pIsMeister)
        {
          //Just chill, play the drone
          if (!tuneFlags[currentTuning])
          {
            if (currentTuning < 6)
            {
              pGoToNote();
            }
            else
            {
              pGoToLastNote();
            }
          }
        }
        else
        {
          if (currentTuning < 6)
          {
            pGoToNote();
          }
          else
          {
            if (tuneFlags[6])
            {
              fadeOutVolume();
            }
            else
            {
              pGoToLastNote();
            }
          }
        }
        tuneFlags[currentTuning] = true;
        if (tuneFlags[6])
        {
         getConcreteParent()->getMotor()->mMotor.stop();
        }

      break;
  }
}

// void PodSensor::updateRealPosition()
// {
//   long mpos = getConcreteParent()->getMotor()->mMotor.currentPosition();
//   long div = mpos/getConcreteParent()->getMotor()->FULL_REVOLUTION;
//   pRealPosition = mpos -(div*getConcreteParent()->getMotor()->FULL_REVOLUTION + pPositions[0]);
//   #if SP_DEBUG
//   Serial.print("(PS) -> updateRealPosition(): pRealPosition ");
//   Serial.println(pRealPosition);
//   Serial.printf("(PS) -> updateRealPosition(): pulse: %i\n", mPulseCount);
//   #endif
// }

void PodSensor::updateMeisterNoteIndex()
{
  //Faking to be the current Note for Tunning
  bool safecheck = false;
  for (int i = 0; i < BUFFER_SIZE; i++)
  {
    if (pNotes[i] >= tuneNotes[0]-tuneRange && pNotes[i] <= tuneNotes[0]+tuneRange )
    {
      pMeisterNoteIndex = i;
      safecheck = true;
    }
  }
  if (!safecheck)
  {
    //Note found, choose a random index to assign the note.
    pMeisterNoteIndex = random(BUFFER_SIZE-1);
    pNotes[pMeisterNoteIndex] = tuneNotes[0];
  }

  #if SP_DEBUG
  Serial.printf("(PS) -> updateMeisterNoteIndex(): meisterNoteIndex %i meisterNote %i",pMeisterNoteIndex,pNotes[pMeisterNoteIndex]);
  #endif
}

void PodSensor::updateNoteToFollowIndex()
{
  //Change the following for the received Meister Note sent by the Meister
  //For now, it is hardcoded to iterate to the notes: A1, A2, A3, A4, A5, A6, A7.

  bool safecheck = false;
  for (int i = random(BUFFER_SIZE); i < BUFFER_SIZE; i++)
  {
    if (pNotes[i] >= tuneNotes[currentTuning]-tuneRange && pNotes[i] <= tuneNotes[currentTuning]+tuneRange )
    {
      if (i != lastIndex)
      {
        if (abs(pPositions[lastIndex]-pPositions[i]) > 500)
        {
          pNoteToFollowIndex = i;
          safecheck = true;
          lastIndex = pNoteToFollowIndex;
          break;
        }
      }
    }
  }

  if (!safecheck)
  {
    //Note found, choose a random index to assign the note.
    while (safecheck == false)
    {
        pNoteToFollowIndex = random(BUFFER_SIZE-1);
        if (pNoteToFollowIndex != lastIndex)
        {
          if (abs(pPositions[lastIndex]-pPositions[pNoteToFollowIndex]) > 500)
          {
            pNotes[pNoteToFollowIndex] = tuneNotes[currentTuning];
            safecheck = true;
            lastIndex = pNoteToFollowIndex;
          }
        }
      }
  }

  #if SP_DEBUG
  Serial.printf("(PS) -> updateNoteToFollowIndex(): pNoteToFollowIndex %i podNote %i",pNoteToFollowIndex,pNotes[pNoteToFollowIndex] );
  #endif
}

void PodSensor::onSensorMessage(uint8_t pMessage, uint16_t pValue) {
  #if SP_DEBUG
    Serial.printf("(PS) -> onSensorMessage(): message: %i - value: %i", pMessage, pValue);
  #endif
  switch(pMessage) {
    case SensorMessages::BUFFER_FULL:
        //Check if it is the Meister to assemble constant turns
      if (pIsMeister)
      {
        //Is Meister, run more
        getConcreteParent()->getMotor()->turnAtSpeed(1600,1);
      }
      else
      {
        fadeOutVolume();
        getConcreteParent()->getMotor()->decelerateToSpeed(50, 0.9);
      }

      break;

      case SensorMessages::SENSOR_READING:
        pNotes[bufferCounter] = map(pValue,0,1023,36,95);
        pPositions[bufferCounter] = getConcreteParent()->getMotor()->mMotor.currentPosition();
        #if SP_DEBUG
          Serial.print("(PS) -> onSensorMessage(): index: ");
          Serial.print(bufferCounter);
          Serial.print(" pNote: ");
          Serial.print(pNotes[bufferCounter]);
          Serial.print(" pPositions: ");
          Serial.println(pPositions[bufferCounter]);
        #endif
        bufferCounter++;
      break;
  }
}

void PodSensor::fadeOutVolume()
{
  #if SP_DEBUG
  Serial.println("(PS) -> PodSensor(): Fading Out");
  #endif
}

void PodSensor::fadeInVolume()
{
  #if SP_DEBUG
  Serial.println("(PS) -> PodSensor(): Fading In");
  #endif
}
<commit_msg>Meister Play Note Bug Fix<commit_after>/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 PodSensor.cpp
 Copyright (c) 2016 Automatic Orchestra

 See the COPYRIGHT file at the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/COPYRIGHT.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 This file is part of Automatic Orchestra. It is subject to the license terms
 in the LICENSE file found in the top-level directory of this distribution and at:
 https://github.com/automatic-orchestra/ao_resonate16/blob/master/LICENSE.

 No part of Automatic Orchestra, including this file, may be copied, modified,
 propagated, or distributed except according to the terms contained in the
 LICENSE file.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/

#include "PodSensor.h"
#include "MotorProxy.h"
#include "CFOSynthesizer.h"
#include "MotorMessages.h"
#include "SensorMessages.h"

#define SP_DEBUG true
#define CHANNEL_DELAY_INCREMENT 15

PodSensor::PodSensor(Orchestra* pParent) : Pod(pParent) {
  // retrieve MIDI channel
  midiChannel = getParent()->getChannel();
  // calculate delay in pulses
  mPulseDelay = midiChannel * CHANNEL_DELAY_INCREMENT;
  // check if is the first Meister (lookup table,)
  if (midiChannel == meisterOrder[0])
  {
    pIsMeister = true;
  }
  else
  {
    pIsMeister = false;
  }
  // apply jakob's magic crescendo preset
  uint8_t presetArray[] = {
    23, 0, 0, 0, 50, 1, 127, 0, 121, 3, 0, 64, 64, 127, 9, 40, 0, 2, 0, 0, 0, 64, 63, 127, 4, 0, 0, 0, 0, 0, 0, 64, 61, 127, 4, 12, 0, 1, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 127, 127, 127, 127, 0, 0, 0, 0, 0, 1, 127, 127, 0, 127
  };
  applyPresets(presetArray);
#if SP_DEBUG
  Serial.printf("(PS) -> constructor(): midi channel is:  %i - meister flag: %i - pulse delay is: %i\n", midiChannel, pIsMeister, mPulseDelay);
#endif
}

PodSensor::~PodSensor() {
}

SensorOrchestra* PodSensor::getConcreteParent() {
  // upcast from base class Orchestra to concrete class SensorOrchestra
  // to gain access to motor and sensor proxy instances.
  // http://www.cplusplus.com/doc/tutorial/typecasting/
  return static_cast<SensorOrchestra*>(getParent());
}

void PodSensor::onClockBeatChange(unsigned long beat) {
  // check initial pulse at zero...
#if SP_DEBUG
  if(!getConcreteParent()->getMotor()->isActive()) {
    #if SP_DEBUG
    Serial.printf("(PS) -> onClockBeatChange(): pulse count is: %i\n", mPulseCount);
    #endif
  }
#endif
  // start motor movement after delay has elapsed
  MotorProxy* motor = getConcreteParent()->getMotor();
  if(mPulseCount >= mPulseDelay && !motor->isActive()) {
    // start acceleration phase
    motor->accelerateToSpeed(1600, 50, 1.25);
    motor->start();
  }

  //Introduction to Development Transition Check

  if (mPulseCount == pulseTimings[0])
  {

    //Update Current Tuning Tone and Meister Flag
    currentTuning = 0;
    if (midiChannel != meisterOrder[currentTuning])
    {
      pIsMeister = false;
    }
    else
    {
      pIsMeister = true;
    }

    if (!pIsMeister)
    {
      #if SP_DEBUG
        Serial.printf("(PS) -> onClockBeatChange(): currentTuning: %i ", currentTuning);
        Serial.println();
      #endif
        pGoToNote();
    }
    else
    {
      //Hold the note

    }
  }

  // ---------------------------------------
  //  play the note based on motor position
  // ---------------------------------------
  // calculate relative postion of values in buffer
  unsigned long pos = getConcreteParent()->getMotor()->mMotor.currentPosition();
  unsigned long firstBufferPos = pPositions[0];
  unsigned long relativePos = firstBufferPos + ((pos - firstBufferPos) % MotorProxy::FULL_REVOLUTION);
  // find matching index of position in buffer
  int index = -1;
  for(int i = 0; i < BUFFER_SIZE; i++) {
    // following index
    int j = (i + 1 == BUFFER_SIZE) ? 0 : i + 1;
    // check buffer values to determine index
    if(relativePos >= pPositions[i] && relativePos < pPositions[j]) {
      index = i;
      break;
    }
  }
  // play note from buffer
  if(index != -1) {
    uint16_t note = pNotes[index];
    if(note != mLastNote) {
      // finally play the new note
      Serial.printf("(PS) -> onClockBeatChange(): Note %i\n",note);
      Music.noteOn(note, 127);
      mLastNote = note;
    }
  } else {
#if SP_DEBUG
    Serial.println("(PS) -> onClockBeatChange(): No matching index found - which shouldn't happen :(");
#endif
  }

  //Development part

    if (mPulseCount == pulseTimings[0])
    {
      #if SP_DEBUG
      Serial.println();
      Serial.println("(PS) -> onClockBeatChange(): change Tuning to 1");
      Serial.println();
      #endif
      currentTuning = 1;
      if (pIsMeister && !tuneFlags[1])
      {
        tuneFlags[1] = true;
        pGoToNote();
      }
    }

    if (mPulseCount == pulseTimings[1])
    {
      #if SP_DEBUG
      Serial.println();
      Serial.println("(PS) -> onClockBeatChange(): change Tuning to 2");
      Serial.println();
      #endif
      currentTuning = 2;
      if (pIsMeister && !tuneFlags[2])
      {
        tuneFlags[2] = true;
        pGoToNote();
      }
    }

    if (mPulseCount == pulseTimings[2])
    {
      #if SP_DEBUG
      Serial.println();
      Serial.println("(PS) -> onClockBeatChange(): change Tuning to 3");
      Serial.println();
      #endif
      currentTuning = 3;
      if (pIsMeister && !tuneFlags[3])
      {
        tuneFlags[3] = true;
        pGoToNote();
      }
    }

    if (mPulseCount == pulseTimings[3])
    {
      #if SP_DEBUG
      Serial.println();
      Serial.println("(PS) -> onClockBeatChange(): change Tuning to 4");
      Serial.println();
      #endif
      currentTuning = 4;
      if (pIsMeister && !tuneFlags[4])
      {
        tuneFlags[4] = true;
        pGoToNote();
      }
    }

    if (mPulseCount == pulseTimings[4])
    {
      #if SP_DEBUG
      Serial.println();
      Serial.println("(PS) -> onClockBeatChange(): change Tuning to 5");
      Serial.println();
      #endif
      currentTuning = 5;
      if (pIsMeister && !tuneFlags[5])
      {
        tuneFlags[5] = true;
        pGoToNote();
      }
    }

    //Final Part

    if (mPulseCount == pulseTimings[5])
    {
      #if SP_DEBUG
      Serial.println();
      Serial.println("(PS) -> onClockBeatChange(): change Tuning to 6");
      Serial.println();
      #endif
      currentTuning = 6;
      if (pIsMeister && !tuneFlags[6])
      {
        tuneFlags[6] = true;
        pGoToNote();
      }
    }

    if (midiChannel != meisterOrder[currentTuning])
    {
      pIsMeister = false;
    }
    else
    {
      pIsMeister = true;
    }

  // therefore increment afterwards
  mPulseCount++;
}

void PodSensor::pGoToNote()
{
  #if SP_DEBUG
  Serial.println("(PS) -> onMotorMessage(): Go to Current Note");
  #endif
  //Search for Note
  // updateRealPosition();
  updateNoteToFollowIndex();
  getConcreteParent()->getMotor()->moveToPosition(
    getConcreteParent()->getMotor()->relativeToAbsolutePosition(pPositions[pNoteToFollowIndex]),
    accelPattern[currentTuning],
    maxSpeedPattern[currentTuning]
  );
}

void PodSensor::pGoToLastNote()
{
  #if SP_DEBUG
  Serial.println("(PS) -> onMotorMessage(): Go to the Last Note");
  #endif
  //Search for Note
  // updateRealPosition();
  updateNoteToFollowIndex();
  getConcreteParent()->getMotor()->moveToPosition(
    getConcreteParent()->getMotor()->relativeToAbsolutePosition(pPositions[pNoteToFollowIndex] + MotorProxy::FULL_REVOLUTION * 3),
    accelPattern[currentTuning],
    maxSpeedPattern[currentTuning]
  );
  lastDrone = true;
}

void PodSensor::onMotorMessage(uint8_t pMessage, uint16_t pValue) {
#if SP_DEBUG
  Serial.printf("(PS) -> onMotorMessage(): message: %i - value: %i\n", pMessage, pValue);
#endif
  switch(pMessage) {
    case MotorMessages::ACCELERATION_DONE:
      // start buffering phase
      getConcreteParent()->getSensor()->startBuffering();
      break;

      case MotorMessages::TURNS_DONE:
        if (pIsMeister)
        {
          #if SP_DEBUG
          Serial.println("(PS) -> onMotorMessage(): Decelerating Meister");
          #endif
          getConcreteParent()->getMotor()->decelerateToSpeed(50, 0.9);
        }
      break;

      case MotorMessages::DECELERATION_DONE:
        if (pIsMeister)
        {
          // updateRealPosition();
          updateMeisterNoteIndex();
        }
        else
        {
          #if SP_DEBUG
          Serial.println("(PS) -> onMotorMessage(): Waiting for pulse ");
          #endif
        }
      break;

      case MotorMessages::TUNING_DONE:

        if (!pIsMeister)
        {
          if (currentTuning < 6)
          {
            pGoToNote();
          }
          else
          {
            if (tuneFlags[6])
            {
              fadeOutVolume();
            }
            else
            {
              pGoToLastNote();
            }
          }
        }
        tuneFlags[currentTuning] = true;
        if (tuneFlags[6])
        {
         getConcreteParent()->getMotor()->mMotor.stop();
        }

      break;
  }
}

// void PodSensor::updateRealPosition()
// {
//   long mpos = getConcreteParent()->getMotor()->mMotor.currentPosition();
//   long div = mpos/getConcreteParent()->getMotor()->FULL_REVOLUTION;
//   pRealPosition = mpos -(div*getConcreteParent()->getMotor()->FULL_REVOLUTION + pPositions[0]);
//   #if SP_DEBUG
//   Serial.print("(PS) -> updateRealPosition(): pRealPosition ");
//   Serial.println(pRealPosition);
//   Serial.printf("(PS) -> updateRealPosition(): pulse: %i\n", mPulseCount);
//   #endif
// }

void PodSensor::updateMeisterNoteIndex()
{
  //Faking to be the current Note for Tunning
  bool safecheck = false;
  for (int i = 0; i < BUFFER_SIZE; i++)
  {
    if (pNotes[i] >= tuneNotes[0]-tuneRange && pNotes[i] <= tuneNotes[0]+tuneRange )
    {
      pMeisterNoteIndex = i;
      safecheck = true;
    }
  }
  if (!safecheck)
  {
    //Note found, choose a random index to assign the note.
    pMeisterNoteIndex = random(BUFFER_SIZE-1);
    pNotes[pMeisterNoteIndex] = tuneNotes[0];
  }

  #if SP_DEBUG
  Serial.printf("(PS) -> updateMeisterNoteIndex(): meisterNoteIndex %i meisterNote %i",pMeisterNoteIndex,pNotes[pMeisterNoteIndex]);
  #endif
}

void PodSensor::updateNoteToFollowIndex()
{
  //Change the following for the received Meister Note sent by the Meister
  //For now, it is hardcoded to iterate to the notes: A1, A2, A3, A4, A5, A6, A7.

  bool safecheck = false;
  for (int i = random(BUFFER_SIZE); i < BUFFER_SIZE; i++)
  {
    if (pNotes[i] >= tuneNotes[currentTuning]-tuneRange && pNotes[i] <= tuneNotes[currentTuning]+tuneRange )
    {
      if (i != lastIndex)
      {
        if (abs(pPositions[lastIndex]-pPositions[i]) > 500)
        {
          pNoteToFollowIndex = i;
          safecheck = true;
          lastIndex = pNoteToFollowIndex;
          break;
        }
      }
    }
  }

  if (!safecheck)
  {
    //Note found, choose a random index to assign the note.
    while (safecheck == false)
    {
        pNoteToFollowIndex = random(BUFFER_SIZE-1);
        if (pNoteToFollowIndex != lastIndex)
        {
          if (abs(pPositions[lastIndex]-pPositions[pNoteToFollowIndex]) > 500)
          {
            pNotes[pNoteToFollowIndex] = tuneNotes[currentTuning];
            safecheck = true;
            lastIndex = pNoteToFollowIndex;
          }
        }
      }
  }

  #if SP_DEBUG
  Serial.printf("(PS) -> updateNoteToFollowIndex(): pNoteToFollowIndex %i podNote %i",pNoteToFollowIndex,pNotes[pNoteToFollowIndex] );
  #endif
}

void PodSensor::onSensorMessage(uint8_t pMessage, uint16_t pValue) {
  #if SP_DEBUG
    Serial.printf("(PS) -> onSensorMessage(): message: %i - value: %i", pMessage, pValue);
  #endif
  switch(pMessage) {
    case SensorMessages::BUFFER_FULL:
        //Check if it is the Meister to assemble constant turns
      if (pIsMeister)
      {
        //Is Meister, run more
        getConcreteParent()->getMotor()->turnAtSpeed(1600,1);
      }
      else
      {
        fadeOutVolume();
        getConcreteParent()->getMotor()->decelerateToSpeed(50, 0.9);
      }

      break;

      case SensorMessages::SENSOR_READING:
        pNotes[bufferCounter] = map(pValue,0,1023,36,95);
        pPositions[bufferCounter] = getConcreteParent()->getMotor()->mMotor.currentPosition();
        #if SP_DEBUG
          Serial.print("(PS) -> onSensorMessage(): index: ");
          Serial.print(bufferCounter);
          Serial.print(" pNote: ");
          Serial.print(pNotes[bufferCounter]);
          Serial.print(" pPositions: ");
          Serial.println(pPositions[bufferCounter]);
        #endif
        bufferCounter++;
      break;
  }
}

void PodSensor::fadeOutVolume()
{
  #if SP_DEBUG
  Serial.println("(PS) -> PodSensor(): Fading Out");
  #endif
}

void PodSensor::fadeInVolume()
{
  #if SP_DEBUG
  Serial.println("(PS) -> PodSensor(): Fading In");
  #endif
}
<|endoftext|>


<commit_before>/**********************************************************************
Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
********************************************************************/

#include "CLW.h"
#include "Renderers/renderer.h"
#include "RenderFactory/clw_render_factory.h"
#include "SceneGraph/camera.h"
#include "scene_io.h"
#include "input_info.h"

#include "utils.h"
#include "render.h"
#include "scene_io.h"
#include "material_io.h"
#include "SceneGraph/light.h"
#include "Output/clwoutput.h"
#include "BaikalIO/image_io.h"

#include "OpenImageIO/imageio.h"

#include <filesystem>
#include <fstream>
#include "XML/tinyxml2.h"

using namespace Baikal;

namespace
{
    std::uint32_t constexpr kNumIterations = 4096;

    bool RoughCompare(float x, float y, float epsilon = std::numeric_limits<float>::epsilon())
    {
    return std::abs(x - y) < epsilon;
    }

    bool RoughCompare(float3 const& l, float3 const& r, float epsilon = std::numeric_limits<float>::epsilon())
    {
        return RoughCompare(l.x, r.x, epsilon) &&
               RoughCompare(l.y, r.y, epsilon) &&
               RoughCompare(l.z, r.z, epsilon);
    }
}

struct OutputInfo
{
    Renderer::OutputType type;
    std::string name;
    // channels number can be only 1 or 3
    int channels_num;
};

// if you need to add new output for saving to disk
// for iterations number counted in spp.xml file
// just put its description in this collection
const std::vector<OutputInfo> kMultipleIteratedOutputs =
{
    {
        { Renderer::OutputType::kColor, "color", 3 },
        { Renderer::OutputType::kAlbedo, "albedo", 3 },
        { Renderer::OutputType::kGloss, "gloss", 1 }
    }
};

// if you need to add new output for saving to disk
// only for the one time
// just put its description in this collection
const std::vector<OutputInfo> kSingleIteratedOutputs =
{
    {
        { Renderer::OutputType::kViewShadingNormal, "view_shading_normal", 3 },
        { Renderer::OutputType::kDepth, "view_shading_depth", 1 }
    }
};

Render::Render(const std::filesystem::path& scene_file,
               size_t output_width,
               size_t output_height)
    : m_width(static_cast<std::uint32_t>(output_width)),
      m_height(static_cast<std::uint32_t>(output_height))
{
    assert(m_width);
    assert(m_height);

    std::vector<CLWPlatform> platforms;
    CLWPlatform::CreateAllPlatforms(platforms);

    bool device_found = false;

    for (const auto& platform : platforms)
    {
        for (auto i = 0u; i < platform.GetDeviceCount(); i++)
        {
            if (platform.GetDevice(i).GetType() == CL_DEVICE_TYPE_GPU)
            {
                m_context = std::make_unique<CLWContext>(CLWContext::Create(platform.GetDevice(i)));
                device_found = true;
                break;
            }
        }

        if (device_found)
            break;
    }

    if (!device_found)
    {
        THROW_EX("can't find device");
    }

    assert(m_context);

    m_factory = std::make_unique<Baikal::ClwRenderFactory>(*m_context, "cache");
    m_renderer = m_factory->CreateRenderer(Baikal::ClwRenderFactory::RendererType::kUnidirectionalPathTracer);
    m_controller = m_factory->CreateSceneController();

    for (auto& output_info : kMultipleIteratedOutputs)
    {
        m_outputs.push_back(m_factory->CreateOutput(m_width, m_height));
        m_renderer->SetOutput(output_info.type, m_outputs.back().get());
    }
    for (auto& output_info : kSingleIteratedOutputs)
    {
        m_outputs.push_back(m_factory->CreateOutput(m_width, m_height));
        m_renderer->SetOutput(output_info.type, m_outputs.back().get());
    }

    if (!std::filesystem::exists(scene_file))
    {
        THROW_EX("There is no any scene file to load");
    }

    // workaround to avoid issues with tiny_object_loader
    auto scene_dir = scene_file.parent_path().string();

    if (scene_dir.back() != '/' || scene_dir.back() != '\\')
    {
#ifdef WIN32
        scene_dir.append("\\");
#else
        scene_dir.append("/");
#endif
    }

    m_scene = Baikal::SceneIo::LoadScene(scene_file.string(), scene_dir);

    // load materials.xml if it exists
    auto materials_file = scene_file.parent_path() / "materials.xml";
    auto mapping_file = scene_file.parent_path() / "mapping.xml";

    if (std::filesystem::exists(materials_file) &&
        std::filesystem::exists(mapping_file))
    {
        auto material_io = Baikal::MaterialIo::CreateMaterialIoXML();
        auto materials = material_io->LoadMaterials(materials_file.string());
        auto mapping = material_io->LoadMaterialMapping(mapping_file.string());

        material_io->ReplaceSceneMaterials(*m_scene, *materials, mapping);
    }
    else
    {
        std::cout << "WARNING: materials.xml or mapping.xml is missed" << std::endl;
    }
}

void Render::UpdateCameraSettings(const CameraInfo& cam_state)
{
    if (cam_state.aperture != m_camera->GetAperture())
    {
        m_camera->SetAperture(cam_state.aperture);
    }

    if (cam_state.focal_length != m_camera->GetFocalLength())
    {
        m_camera->SetFocalLength(cam_state.focal_length);
    }

    if (cam_state.focus_distance != m_camera->GetFocusDistance())
    {
        m_camera->SetFocusDistance(cam_state.focus_distance);
    }

    auto cur_pos = m_camera->GetPosition();
    auto at = m_camera->GetForwardVector();
    auto up = m_camera->GetUpVector();

    if (!RoughCompare(cur_pos, cam_state.pos) ||
        !RoughCompare(at, cam_state.at) ||
        !RoughCompare(up, cam_state.up))
    {
        m_camera->LookAt(cam_state.pos, cam_state.at, cam_state.up);
    }
}

void Render::SaveOutput(const OutputInfo& info,
                        const std::string& name,
                        bool gamma_correction_enabled,
                        const std::filesystem::path& output_dir)
{
    OIIO_NAMESPACE_USING;

    auto output = m_renderer->GetOutput(info.type);

    assert(output);

    auto buffer = static_cast<Baikal::ClwOutput*>(output)->data();

    std::vector<RadeonRays::float3> output_data(buffer.GetElementCount());

    output->GetData(output_data.data());

    std::vector<float> image_data(info.channels_num * m_width * m_height);

    float* dst_row = image_data.data();

    if (gamma_correction_enabled &&
       (info.type == Renderer::OutputType::kColor) &&
       (info.channels_num == 3))
    {
        for (auto y = 0u; y < m_height; ++y)
        {
            for (auto x = 0u; x < m_width; ++x)
            {
                float3 val = output_data[(m_height - 1 - y) * m_width + x];
                // "The 4-th pixel component is a count of accumulated samples.
                // It can be different for every pixel in case of adaptive sampling.
                // So, we need to normalize pixel values here".
                val *= (1.f / val.w);
                // gamma corection
                dst_row[info.channels_num * x] = std::pow(val.x, 1.f / 2.2f);
                dst_row[info.channels_num * x + 1] = std::pow(val.y, 1.f / 2.2f);
                dst_row[info.channels_num * x + 2] = std::pow(val.z, 1.f / 2.2f);
            }
            dst_row += info.channels_num * m_width;
        }
    }
    else
    {
        for (auto y = 0u; y < m_height; ++y)
        {
            for (auto x = 0u; x < m_width; ++x)
            {
                float3 val = output_data[(m_height - 1 - y) * m_width + x];
                // "The 4-th pixel component is a count of accumulated samples.
                // It can be different for every pixel in case of adaptive sampling.
                // So, we need to normalize pixel values here".
                val *= (1.f / val.w);

                if (info.channels_num == 3)
                {
                    int dst_pixel = y * m_width + x;
                    // invert the image
                    dst_row[info.channels_num * x] = val.x;
                    dst_row[info.channels_num * x + 1] = val.y;
                    dst_row[info.channels_num * x + 2] = val.z;
                }
                else // info.channels_num = 1
                {
                    // invert the image
                    dst_row[x] = val.x;
                }
            }
            dst_row += info.channels_num * m_width;
        }
    }

    std::filesystem::path file_name = output_dir;
    file_name.append(name);

    std::ofstream f (file_name.string(), std::ofstream::binary);

    f.write(reinterpret_cast<const char*>(image_data.data()),
            sizeof(float) * image_data.size());
}

void Render::SetLightConfig(const std::vector<LightInfo>& lights)
{
    for (const auto& light : lights)
    {
        Light::Ptr light_instance;

        if (light.type == "point")
        {
            light_instance = PointLight::Create();
        }
        else if (light.type == "direct")
        {
            light_instance = DirectionalLight::Create();
        }
        else if (light.type == "spot")
        {
            light_instance = SpotLight::Create();
            SpotLight::Ptr spot = std::dynamic_pointer_cast<SpotLight>(light_instance);
            spot->SetConeShape(light.cs);
        }
        else if (light.type == "ibl")
        {
            light_instance = ImageBasedLight::Create();

            ImageBasedLight::Ptr ibl = std::dynamic_pointer_cast<
                ImageBasedLight>(light_instance);

            auto image_io(ImageIo::CreateImageIo());

            // check that texture file is exists
            auto texure_path = std::filesystem::absolute(std::filesystem::relative(light.texture));
            if (!std::filesystem::exists(texure_path))
            {
                THROW_EX("texture image doesn't exist on specified path")
            }

            Texture::Ptr tex = image_io->LoadImage(texure_path.string());
            ibl->SetTexture(tex);
            ibl->SetMultiplier(light.mul);
        }
        else
        {
            THROW_EX("unsupported light type")
        }

        light_instance->SetPosition(light.pos);
        light_instance->SetDirection(light.dir);
        light_instance->SetEmittedRadiance(light.rad);
        m_scene->AttachLight(light_instance);
    }
}

void Render::GenerateDataset(const std::vector<CameraInfo>& cam_states,
                             const std::vector<LightInfo>& light_states,
                             const std::vector<size_t>& spp,
                             const std::filesystem::path& output_dir,
                             bool gamma_correction_enabled,
                             size_t start_cam_id)
{
    using namespace RadeonRays;

    if (!std::filesystem::is_directory(output_dir))
    {
        THROW_EX("incorrect output directory signature");
    }

    // check if number of samples to render wasn't specified
    if (spp.empty())
    {
        THROW_EX("spp collection is empty");
    }

    SetLightConfig(light_states);

    auto sorted_spp = spp;
    std::sort(sorted_spp.begin(), sorted_spp.end());

    sorted_spp.erase(std::unique(sorted_spp.begin(), sorted_spp.end()), sorted_spp.end());

    if (sorted_spp.front() <= 0)
    {
        THROW_EX("spp should be positive");
    }

    for (const auto& cam_state : cam_states)
    {
        // create camera if it wasn't  done earlier
        if (!m_camera)
        {
            m_camera = Baikal::PerspectiveCamera::Create(cam_state.at,
                                                         cam_state.pos,
                                                         cam_state.up);

            // default sensor width
            float sensor_width = 0.036f;
            float inverserd_aspect_ration = static_cast<float>(m_height) /
                                            static_cast<float>(m_width);
            float sensor_height = sensor_width * inverserd_aspect_ration;

            m_camera->SetSensorSize(float2(0.036f, sensor_height));
            m_camera->SetDepthRange(float2(0.0f, 100000.f));

            m_scene->SetCamera(m_camera);
        }

        UpdateCameraSettings(cam_state);

        for (const auto& output: m_outputs)
        {
            output->Clear(float3());
        }

        // recompile scene cause of changing camera pos and settings
        m_controller->CompileScene(m_scene);
        auto& scene = m_controller->GetCachedScene(m_scene);

        auto spp_iter = sorted_spp.begin();

        for (auto i = 1u; i <= sorted_spp.back(); i++)
        {
            m_renderer->Render(scene);

            if (i == 1)
            {
                for (const auto& output : kSingleIteratedOutputs)
                {
                    std::stringstream ss;

                    ss << "cam_" << start_cam_id << "_"
                        << output.name << ".bin";

                    SaveOutput(output,
                               ss.str(),
                               gamma_correction_enabled,
                               output_dir);
                }
            }

            if (*spp_iter == i)
            {
                for (const auto& output : kMultipleIteratedOutputs)
                {
                    std::stringstream ss;

                    ss << "cam_" << start_cam_id << "_"
                        << output.name << "_spp_" << i << ".bin";

                    SaveOutput(output,
                                ss.str(),
                                gamma_correction_enabled,
                                output_dir);
                }
                ++spp_iter;
                std::cout << "cam_" << start_cam_id << "_spp_" << i << "_generated" << std::endl;
            }
        }

        start_cam_id++;
    }
}

Render::~Render() = default;
<commit_msg>Deleted changing camera pos<commit_after>/**********************************************************************
Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
********************************************************************/

#include "CLW.h"
#include "Renderers/renderer.h"
#include "RenderFactory/clw_render_factory.h"
#include "SceneGraph/camera.h"
#include "scene_io.h"
#include "input_info.h"

#include "utils.h"
#include "render.h"
#include "scene_io.h"
#include "material_io.h"
#include "SceneGraph/light.h"
#include "Output/clwoutput.h"
#include "BaikalIO/image_io.h"

#include "OpenImageIO/imageio.h"

#include <filesystem>
#include <fstream>
#include "XML/tinyxml2.h"

using namespace Baikal;

struct OutputInfo
{
    Renderer::OutputType type;
    std::string name;
    // channels number can be only 1 or 3
    int channels_num;
};

// if you need to add new output for saving to disk
// for iterations number counted in spp.xml file
// just put its description in this collection
const std::vector<OutputInfo> kMultipleIteratedOutputs =
{
    {
        { Renderer::OutputType::kColor, "color", 3 },
        { Renderer::OutputType::kAlbedo, "albedo", 3 },
        { Renderer::OutputType::kGloss, "gloss", 1 }
    }
};

// if you need to add new output for saving to disk
// only for the one time
// just put its description in this collection
const std::vector<OutputInfo> kSingleIteratedOutputs =
{
    {
        { Renderer::OutputType::kViewShadingNormal, "view_shading_normal", 3 },
        { Renderer::OutputType::kDepth, "view_shading_depth", 1 }
    }
};

Render::Render(const std::filesystem::path& scene_file,
               size_t output_width,
               size_t output_height)
    : m_width(static_cast<std::uint32_t>(output_width)),
      m_height(static_cast<std::uint32_t>(output_height))
{
    assert(m_width);
    assert(m_height);

    std::vector<CLWPlatform> platforms;
    CLWPlatform::CreateAllPlatforms(platforms);

    bool device_found = false;

    for (const auto& platform : platforms)
    {
        for (auto i = 0u; i < platform.GetDeviceCount(); i++)
        {
            if (platform.GetDevice(i).GetType() == CL_DEVICE_TYPE_GPU)
            {
                m_context = std::make_unique<CLWContext>(CLWContext::Create(platform.GetDevice(i)));
                device_found = true;
                break;
            }
        }

        if (device_found)
            break;
    }

    if (!device_found)
    {
        THROW_EX("can't find device");
    }

    assert(m_context);

    m_factory = std::make_unique<Baikal::ClwRenderFactory>(*m_context, "cache");
    m_renderer = m_factory->CreateRenderer(Baikal::ClwRenderFactory::RendererType::kUnidirectionalPathTracer);
    m_controller = m_factory->CreateSceneController();

    for (auto& output_info : kMultipleIteratedOutputs)
    {
        m_outputs.push_back(m_factory->CreateOutput(m_width, m_height));
        m_renderer->SetOutput(output_info.type, m_outputs.back().get());
    }
    for (auto& output_info : kSingleIteratedOutputs)
    {
        m_outputs.push_back(m_factory->CreateOutput(m_width, m_height));
        m_renderer->SetOutput(output_info.type, m_outputs.back().get());
    }

    if (!std::filesystem::exists(scene_file))
    {
        THROW_EX("There is no any scene file to load");
    }

    // workaround to avoid issues with tiny_object_loader
    auto scene_dir = scene_file.parent_path().string();

    if (scene_dir.back() != '/' || scene_dir.back() != '\\')
    {
#ifdef WIN32
        scene_dir.append("\\");
#else
        scene_dir.append("/");
#endif
    }

    m_scene = Baikal::SceneIo::LoadScene(scene_file.string(), scene_dir);

    // load materials.xml if it exists
    auto materials_file = scene_file.parent_path() / "materials.xml";
    auto mapping_file = scene_file.parent_path() / "mapping.xml";

    if (std::filesystem::exists(materials_file) &&
        std::filesystem::exists(mapping_file))
    {
        auto material_io = Baikal::MaterialIo::CreateMaterialIoXML();
        auto materials = material_io->LoadMaterials(materials_file.string());
        auto mapping = material_io->LoadMaterialMapping(mapping_file.string());

        material_io->ReplaceSceneMaterials(*m_scene, *materials, mapping);
    }
    else
    {
        std::cout << "WARNING: materials.xml or mapping.xml is missed" << std::endl;
    }
}

void Render::UpdateCameraSettings(const CameraInfo& cam_state)
{
    if (cam_state.aperture != m_camera->GetAperture())
    {
        m_camera->SetAperture(cam_state.aperture);
    }

    if (cam_state.focal_length != m_camera->GetFocalLength())
    {
        m_camera->SetFocalLength(cam_state.focal_length);
    }

    if (cam_state.focus_distance != m_camera->GetFocusDistance())
    {
        m_camera->SetFocusDistance(cam_state.focus_distance);
    }

    m_camera->LookAt(cam_state.pos, cam_state.at, cam_state.up);
}

void Render::SaveOutput(const OutputInfo& info,
                        const std::string& name,
                        bool gamma_correction_enabled,
                        const std::filesystem::path& output_dir)
{
    OIIO_NAMESPACE_USING;

    auto output = m_renderer->GetOutput(info.type);

    assert(output);

    auto buffer = static_cast<Baikal::ClwOutput*>(output)->data();

    std::vector<RadeonRays::float3> output_data(buffer.GetElementCount());

    output->GetData(output_data.data());

    std::vector<float> image_data(info.channels_num * m_width * m_height);

    float* dst_row = image_data.data();

    if (gamma_correction_enabled &&
       (info.type == Renderer::OutputType::kColor) &&
       (info.channels_num == 3))
    {
        for (auto y = 0u; y < m_height; ++y)
        {
            for (auto x = 0u; x < m_width; ++x)
            {
                float3 val = output_data[(m_height - 1 - y) * m_width + x];
                // "The 4-th pixel component is a count of accumulated samples.
                // It can be different for every pixel in case of adaptive sampling.
                // So, we need to normalize pixel values here".
                val *= (1.f / val.w);
                // gamma corection
                dst_row[info.channels_num * x] = std::pow(val.x, 1.f / 2.2f);
                dst_row[info.channels_num * x + 1] = std::pow(val.y, 1.f / 2.2f);
                dst_row[info.channels_num * x + 2] = std::pow(val.z, 1.f / 2.2f);
            }
            dst_row += info.channels_num * m_width;
        }
    }
    else
    {
        for (auto y = 0u; y < m_height; ++y)
        {
            for (auto x = 0u; x < m_width; ++x)
            {
                float3 val = output_data[(m_height - 1 - y) * m_width + x];
                // "The 4-th pixel component is a count of accumulated samples.
                // It can be different for every pixel in case of adaptive sampling.
                // So, we need to normalize pixel values here".
                val *= (1.f / val.w);

                if (info.channels_num == 3)
                {
                    int dst_pixel = y * m_width + x;
                    // invert the image
                    dst_row[info.channels_num * x] = val.x;
                    dst_row[info.channels_num * x + 1] = val.y;
                    dst_row[info.channels_num * x + 2] = val.z;
                }
                else // info.channels_num = 1
                {
                    // invert the image
                    dst_row[x] = val.x;
                }
            }
            dst_row += info.channels_num * m_width;
        }
    }

    std::filesystem::path file_name = output_dir;
    file_name.append(name);

    std::ofstream f (file_name.string(), std::ofstream::binary);

    f.write(reinterpret_cast<const char*>(image_data.data()),
            sizeof(float) * image_data.size());
}

void Render::SetLightConfig(const std::vector<LightInfo>& lights)
{
    for (const auto& light : lights)
    {
        Light::Ptr light_instance;

        if (light.type == "point")
        {
            light_instance = PointLight::Create();
        }
        else if (light.type == "direct")
        {
            light_instance = DirectionalLight::Create();
        }
        else if (light.type == "spot")
        {
            light_instance = SpotLight::Create();
            SpotLight::Ptr spot = std::dynamic_pointer_cast<SpotLight>(light_instance);
            spot->SetConeShape(light.cs);
        }
        else if (light.type == "ibl")
        {
            light_instance = ImageBasedLight::Create();

            ImageBasedLight::Ptr ibl = std::dynamic_pointer_cast<
                ImageBasedLight>(light_instance);

            auto image_io(ImageIo::CreateImageIo());

            // check that texture file is exists
            auto texure_path = std::filesystem::absolute(std::filesystem::relative(light.texture));
            if (!std::filesystem::exists(texure_path))
            {
                THROW_EX("texture image doesn't exist on specified path")
            }

            Texture::Ptr tex = image_io->LoadImage(texure_path.string());
            ibl->SetTexture(tex);
            ibl->SetMultiplier(light.mul);
        }
        else
        {
            THROW_EX("unsupported light type")
        }

        light_instance->SetPosition(light.pos);
        light_instance->SetDirection(light.dir);
        light_instance->SetEmittedRadiance(light.rad);
        m_scene->AttachLight(light_instance);
    }
}

void Render::GenerateDataset(const std::vector<CameraInfo>& cam_states,
                             const std::vector<LightInfo>& light_states,
                             const std::vector<size_t>& spp,
                             const std::filesystem::path& output_dir,
                             bool gamma_correction_enabled,
                             size_t start_cam_id)
{
    using namespace RadeonRays;

    if (!std::filesystem::is_directory(output_dir))
    {
        THROW_EX("incorrect output directory signature");
    }

    // check if number of samples to render wasn't specified
    if (spp.empty())
    {
        THROW_EX("spp collection is empty");
    }

    SetLightConfig(light_states);

    auto sorted_spp = spp;
    std::sort(sorted_spp.begin(), sorted_spp.end());

    sorted_spp.erase(std::unique(sorted_spp.begin(), sorted_spp.end()), sorted_spp.end());

    if (sorted_spp.front() <= 0)
    {
        THROW_EX("spp should be positive");
    }

    for (const auto& cam_state : cam_states)
    {
        // create camera if it wasn't  done earlier
        if (!m_camera)
        {
            m_camera = Baikal::PerspectiveCamera::Create(cam_state.at,
                                                         cam_state.pos,
                                                         cam_state.up);

            // default sensor width
            float sensor_width = 0.036f;
            float inverserd_aspect_ration = static_cast<float>(m_height) /
                                            static_cast<float>(m_width);
            float sensor_height = sensor_width * inverserd_aspect_ration;

            m_camera->SetSensorSize(float2(0.036f, sensor_height));
            m_camera->SetDepthRange(float2(0.0f, 100000.f));

            m_scene->SetCamera(m_camera);
        }

        UpdateCameraSettings(cam_state);

        for (const auto& output: m_outputs)
        {
            output->Clear(float3());
        }

        // recompile scene cause of changing camera pos and settings
        m_controller->CompileScene(m_scene);
        auto& scene = m_controller->GetCachedScene(m_scene);

        auto spp_iter = sorted_spp.begin();

        for (auto i = 1u; i <= sorted_spp.back(); i++)
        {
            m_renderer->Render(scene);

            if (i == 1)
            {
                for (const auto& output : kSingleIteratedOutputs)
                {
                    std::stringstream ss;

                    ss << "cam_" << start_cam_id << "_"
                        << output.name << ".bin";

                    SaveOutput(output,
                               ss.str(),
                               gamma_correction_enabled,
                               output_dir);
                }
            }

            if (*spp_iter == i)
            {
                for (const auto& output : kMultipleIteratedOutputs)
                {
                    std::stringstream ss;

                    ss << "cam_" << start_cam_id << "_"
                        << output.name << "_spp_" << i << ".bin";

                    SaveOutput(output,
                                ss.str(),
                                gamma_correction_enabled,
                                output_dir);
                }
                ++spp_iter;
                std::cout << "cam_" << start_cam_id << "_spp_" << i << "_generated" << std::endl;
            }
        }

        start_cam_id++;
    }
}

Render::~Render() = default;
<|endoftext|>


<commit_before><commit_msg>fix scrolling<commit_after><|endoftext|>


<commit_before>// Copyright 2016 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <Reduction.hpp>

namespace TuneBench {

ReductionConf::ReductionConf() : isa::OpenCL::KernelConf(), nrItemsPerBlock(1) {}

std::string ReductionConf::print() const {
  return isa::utils::toString(nrItemsPerBlock) + " " + isa::utils::toString(vector) + " " + isa::OpenCL::KernelConf::print();
}

std::string * getReductionOpenCL(const ReductionConf & conf, const std::string & inputDataName, const std::string & outputDataName) {
  std::string * code = new std::string();
  std::string vectorDataName;

  if ( conf.getVector() == 1 ) {
    vectorDataName = inputDataName;
  } else {
    vectorDataName = inputDataName + std::to_string(conf.getVector());
  }
  // Begin kernel's template
  *code = "__kernel void reduction(__global const " + vectorDataName + " * const restrict input, __global " + outputDataName + " * const restrict output) {\n"
    "const unsigned int firstItem = (get_group_id(0) * " + isa::utils::toString(conf.getNrItemsPerBlock()) + ") + get_local_id(0);\n"
    "__local " + outputDataName + " buffer[" + isa::utils::toString(conf.getNrThreadsD0()) + "];\n"
    "<%DEF%>"
    "\n"
    "// First compute phase\n"
    "for ( unsigned int item = firstItem; item < (firstItem + " + isa::utils::toString(conf.getNrItemsPerBlock()) + "); item += " + isa::utils::toString(conf.getNrThreadsD0() * conf.getNrItemsD0()) + " ) {\n"
    "<%COMPUTE%>"
    "}\n"
    "// In-thread reduce phase\n"
    + outputDataName + " accumulator = 0;\n"
    "<%REDUCE%>";
  if ( conf.getVector() == 1 ) {
    *code += "accumulator = accumulator0;\n";
  } else if ( conf.getVector() == 2 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n";
  } else if ( conf.getVector() == 3 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n";
  } else if ( conf.getVector() == 4 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n"
      "accumulator += accumulator0.s3;\n";
  } else if ( conf.getVector() == 8 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n"
      "accumulator += accumulator0.s3;\n"
      "accumulator += accumulator0.s4;\n"
      "accumulator += accumulator0.s5;\n"
      "accumulator += accumulator0.s6;\n"
      "accumulator += accumulator0.s7;\n";
  } else if ( conf.getVector() == 16 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n"
      "accumulator += accumulator0.s3;\n"
      "accumulator += accumulator0.s4;\n"
      "accumulator += accumulator0.s5;\n"
      "accumulator += accumulator0.s6;\n"
      "accumulator += accumulator0.s7;\n"
      "accumulator += accumulator0.s8;\n"
      "accumulator += accumulator0.s9;\n"
      "accumulator += accumulator0.sA;\n"
      "accumulator += accumulator0.sB;\n"
      "accumulator += accumulator0.sC;\n"
      "accumulator += accumulator0.sD;\n"
      "accumulator += accumulator0.sE;\n"
      "accumulator += accumulator0.sF;\n";
  }
  *code += "buffer[get_local_id(0)] = accumulator;\n"
    "barrier(CLK_LOCAL_MEM_FENCE);\n"
    "// Parallel reduce phase\n"
    "unsigned int threshold = " + isa::utils::toString(conf.getNrThreadsD0() / 2) + ";\n"
    "for ( unsigned int item = get_local_id(0); threshold > 0; threshold /= 2 ) {\n"
    "if ( item < threshold ) {\n"
    "accumulator += buffer[item + threshold];\n"
    "buffer[item] = accumulator;\n"
    "}\n"
    "barrier(CLK_LOCAL_MEM_FENCE);\n"
    "}\n"
    "// Store\n"
    "if ( get_local_id(0) == 0 ) {\n"
    "output[get_group_id(0)] = accumulator;\n"
    "}\n"
    "}\n";
  std::string def_sTemplate = vectorDataName + " accumulator<%NUM%> = 0;\n";
  std::string compute_sTemplate = "accumulator<%NUM%> += input[item + <%OFFSET%>];\n";
  std::string reduce_sTemplate = "accumulator0 += accumulator<%NUM%>;\n";
  // End kernel's template

  std::string * def_s = new std::string();
  std::string * compute_s = new std::string();
  std::string * reduce_s = new std::string();

  for ( unsigned int item = 0; item < conf.getNrItemsD0(); item++ ) {
    std::string item_s = isa::utils::toString(item);
    std::string offset_s = isa::utils::toString(item * conf.getNrThreadsD0());
    std::string * temp = 0;

    temp = isa::utils::replace(&def_sTemplate, "<%NUM%>", item_s);
    def_s->append(*temp);
    delete temp;
    temp = isa::utils::replace(&compute_sTemplate, "<%NUM%>", item_s);
    if ( item == 0 ) {
      std::string empty_s("");
      temp = isa::utils::replace(temp, " + <%OFFSET%>", empty_s, true);
    } else {
      temp = isa::utils::replace(temp, "<%OFFSET%>", offset_s, true);
    }
    compute_s->append(*temp);
    delete temp;
    if ( item > 0 ) {
      temp = isa::utils::replace(&reduce_sTemplate, "<%NUM%>", item_s);
      reduce_s->append(*temp);
      delete temp;
    }
  }
  code = isa::utils::replace(code, "<%DEF%>", *def_s, true);
  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);
  code = isa::utils::replace(code, "<%REDUCE%>", *reduce_s, true);
  delete def_s;
  delete compute_s;
  delete reduce_s;

  return code;
}

} // TuneBench

<commit_msg>Wrong addressing of the input vector.<commit_after>// Copyright 2016 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <Reduction.hpp>

namespace TuneBench {

ReductionConf::ReductionConf() : isa::OpenCL::KernelConf(), nrItemsPerBlock(1) {}

std::string ReductionConf::print() const {
  return isa::utils::toString(nrItemsPerBlock) + " " + isa::utils::toString(vector) + " " + isa::OpenCL::KernelConf::print();
}

std::string * getReductionOpenCL(const ReductionConf & conf, const std::string & inputDataName, const std::string & outputDataName) {
  std::string * code = new std::string();
  std::string vectorDataName;

  if ( conf.getVector() == 1 ) {
    vectorDataName = inputDataName;
  } else {
    vectorDataName = inputDataName + std::to_string(conf.getVector());
  }
  // Begin kernel's template
  *code = "__kernel void reduction(__global const " + vectorDataName + " * const restrict input, __global " + outputDataName + " * const restrict output) {\n"
    "const unsigned int firstItem = (get_group_id(0) * " + isa::utils::toString(conf.getNrItemsPerBlock() / conf.getVector()) + ") + get_local_id(0);\n"
    "__local " + outputDataName + " buffer[" + isa::utils::toString(conf.getNrThreadsD0()) + "];\n"
    "<%DEF%>"
    "\n"
    "// First compute phase\n"
    "for ( unsigned int item = firstItem; item < (firstItem + " + isa::utils::toString(conf.getNrItemsPerBlock() / conf.getVector()) + "); item += " + isa::utils::toString(conf.getNrThreadsD0() * conf.getNrItemsD0()) + " ) {\n"
    "<%COMPUTE%>"
    "}\n"
    "// In-thread reduce phase\n"
    + outputDataName + " accumulator = 0;\n"
    "<%REDUCE%>";
  if ( conf.getVector() == 1 ) {
    *code += "accumulator = accumulator0;\n";
  } else if ( conf.getVector() == 2 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n";
  } else if ( conf.getVector() == 3 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n";
  } else if ( conf.getVector() == 4 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n"
      "accumulator += accumulator0.s3;\n";
  } else if ( conf.getVector() == 8 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n"
      "accumulator += accumulator0.s3;\n"
      "accumulator += accumulator0.s4;\n"
      "accumulator += accumulator0.s5;\n"
      "accumulator += accumulator0.s6;\n"
      "accumulator += accumulator0.s7;\n";
  } else if ( conf.getVector() == 16 ) {
    *code += "accumulator = accumulator0.s0;\n"
      "accumulator += accumulator0.s1;\n"
      "accumulator += accumulator0.s2;\n"
      "accumulator += accumulator0.s3;\n"
      "accumulator += accumulator0.s4;\n"
      "accumulator += accumulator0.s5;\n"
      "accumulator += accumulator0.s6;\n"
      "accumulator += accumulator0.s7;\n"
      "accumulator += accumulator0.s8;\n"
      "accumulator += accumulator0.s9;\n"
      "accumulator += accumulator0.sA;\n"
      "accumulator += accumulator0.sB;\n"
      "accumulator += accumulator0.sC;\n"
      "accumulator += accumulator0.sD;\n"
      "accumulator += accumulator0.sE;\n"
      "accumulator += accumulator0.sF;\n";
  }
  *code += "buffer[get_local_id(0)] = accumulator;\n"
    "barrier(CLK_LOCAL_MEM_FENCE);\n"
    "// Parallel reduce phase\n"
    "unsigned int threshold = " + isa::utils::toString(conf.getNrThreadsD0() / 2) + ";\n"
    "for ( unsigned int item = get_local_id(0); threshold > 0; threshold /= 2 ) {\n"
    "if ( item < threshold ) {\n"
    "accumulator += buffer[item + threshold];\n"
    "buffer[item] = accumulator;\n"
    "}\n"
    "barrier(CLK_LOCAL_MEM_FENCE);\n"
    "}\n"
    "// Store\n"
    "if ( get_local_id(0) == 0 ) {\n"
    "output[get_group_id(0)] = accumulator;\n"
    "}\n"
    "}\n";
  std::string def_sTemplate = vectorDataName + " accumulator<%NUM%> = 0;\n";
  std::string compute_sTemplate = "accumulator<%NUM%> += input[item + <%OFFSET%>];\n";
  std::string reduce_sTemplate = "accumulator0 += accumulator<%NUM%>;\n";
  // End kernel's template

  std::string * def_s = new std::string();
  std::string * compute_s = new std::string();
  std::string * reduce_s = new std::string();

  for ( unsigned int item = 0; item < conf.getNrItemsD0(); item++ ) {
    std::string item_s = isa::utils::toString(item);
    std::string offset_s = isa::utils::toString(item * conf.getNrThreadsD0());
    std::string * temp = 0;

    temp = isa::utils::replace(&def_sTemplate, "<%NUM%>", item_s);
    def_s->append(*temp);
    delete temp;
    temp = isa::utils::replace(&compute_sTemplate, "<%NUM%>", item_s);
    if ( item == 0 ) {
      std::string empty_s("");
      temp = isa::utils::replace(temp, " + <%OFFSET%>", empty_s, true);
    } else {
      temp = isa::utils::replace(temp, "<%OFFSET%>", offset_s, true);
    }
    compute_s->append(*temp);
    delete temp;
    if ( item > 0 ) {
      temp = isa::utils::replace(&reduce_sTemplate, "<%NUM%>", item_s);
      reduce_s->append(*temp);
      delete temp;
    }
  }
  code = isa::utils::replace(code, "<%DEF%>", *def_s, true);
  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);
  code = isa::utils::replace(code, "<%REDUCE%>", *reduce_s, true);
  delete def_s;
  delete compute_s;
  delete reduce_s;

  return code;
}

} // TuneBench

<|endoftext|>