<commit_before>/***************************************************************************
                          texteffectplugin.cpp  -  description
                             -------------------
    begin                : jeu nov 14 2002
    copyright            : (C) 2002 by Olivier Goffart
    email                : ogoffart@tiscalinet.be
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include <kdebug.h>
#include <kgenericfactory.h>

#include "kopetemessagemanagerfactory.h"

#include "texteffectplugin.h"
#include "texteffectconfig.h"

typedef KGenericFactory<TextEffectPlugin> TextEffectPluginFactory;
K_EXPORT_COMPONENT_FACTORY( kopete_texteffect, TextEffectPluginFactory( "kopete_texteffect" )  )

TextEffectPlugin::TextEffectPlugin( QObject *parent, const char *name, const QStringList &/*args*/ )
: KopetePlugin( TextEffectPluginFactory::instance(), parent, name )
{
	if( !pluginStatic_ )
		pluginStatic_=this;

	m_config = new TextEffectConfig;

	connect ( this , SIGNAL( settingsChanged() ) , this , SLOT( slotSettingsChanged() ) );

	connect( KopeteMessageManagerFactory::factory(),
		SIGNAL( aboutToSend( KopeteMessage & ) ),
		SLOT( slotOutgoingMessage( KopeteMessage & ) ) );

	 last_color=0;
}

TextEffectPlugin::~TextEffectPlugin()
{
	delete m_config;
	pluginStatic_ = 0L;
}

TextEffectPlugin* TextEffectPlugin::plugin()
{
	return pluginStatic_ ;
}

TextEffectPlugin* TextEffectPlugin::pluginStatic_ = 0L;

void TextEffectPlugin::slotOutgoingMessage( KopeteMessage& msg )
{
	if(msg.direction() != KopeteMessage::Outbound)
		return;

	QStringList colors=m_config->colors();

	if(m_config->colorChar() || m_config->colorWords() || m_config->lamer() || m_config->waves() )
	{
		QString original=msg.plainBody();
		QString resultat;

		unsigned int c=0;
		bool wavein=false;

		for(unsigned int f=0;f<original.length();f++)
		{
			char x=original[f].latin1();
			if(f==0 || m_config->colorChar() || (m_config->colorWords() && x==' ' ))
			{
				if(f!=0)
					resultat+="";
				resultat+="colorRandom())
					c=rand()%colors.count();
				else
				{
					c++;
					if(c >= colors.count())
						c=0;
				}
				resultat+="\">";
			}
			switch (x)
			{
				case '>':
					resultat+=">";
					break;
				case '<':
					resultat+="<";
					break;
				case '&':
					resultat+="&";
					break;
				case '\n':
					resultat+="
";
				case 'a':
				case 'A':
					if(m_config->lamer())
					{
						resultat+="4";
						break;
					}
				case 'e':
				case 'E':
					if(m_config->lamer())
					{
						resultat+="3";
						break;
					}
				case 'i':
				case 'I':
					if(m_config->lamer())
					{
						resultat+="1";
						break;
					}
				case 'l':
				case 'L':
					if(m_config->lamer())
					{
						resultat+="|";
						break;
					}
				case 't':
				case 'T':
					if(m_config->lamer())
					{
						resultat+="7";
						break;
					}
				case 's':
				case 'S':
					if(m_config->lamer())
					{
						resultat+="5";
						break;
					}
				case 'o':
				case 'O':
					if(m_config->lamer())
					{
						resultat+="0";
						break;
					}
				default:
					if(m_config->waves())
					{
						QString q=QString(QChar(x));
						resultat+= wavein ? q.lower() : q.upper();
						wavein=!wavein;
					}
					else
						resultat+=x;
					break;
			}
		}
		if( m_config->colorChar() || m_config->colorWords() )
			resultat+="";
		msg.setBody(resultat,KopeteMessage::RichText);
	}

	if(m_config->colorLines())
	{
		if(m_config->colorRandom())
		{
			last_color=rand()%colors.count();
		}
		else
		{
			last_color++;
			if(last_color >= colors.count())
				last_color=0;
		}

		msg.setFg(QColor (colors[last_color]));
	}
}

void TextEffectPlugin::slotSettingsChanged()
{
	m_config->load();
}

#include "texteffectplugin.moc"

<commit_msg>Fix Bug 62353: Allow to send in other languages with the Text Effect plugin<commit_after>/***************************************************************************
                          texteffectplugin.cpp  -  description
                             -------------------
    begin                : jeu nov 14 2002
    copyright            : (C) 2002 by Olivier Goffart
    email                : ogoffart@tiscalinet.be
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include <kdebug.h>
#include <kgenericfactory.h>

#include "kopetemessagemanagerfactory.h"

#include "texteffectplugin.h"
#include "texteffectconfig.h"

typedef KGenericFactory<TextEffectPlugin> TextEffectPluginFactory;
K_EXPORT_COMPONENT_FACTORY( kopete_texteffect, TextEffectPluginFactory( "kopete_texteffect" )  )

TextEffectPlugin::TextEffectPlugin( QObject *parent, const char *name, const QStringList &/*args*/ )
: KopetePlugin( TextEffectPluginFactory::instance(), parent, name )
{
	if( !pluginStatic_ )
		pluginStatic_=this;

	m_config = new TextEffectConfig;

	connect ( this , SIGNAL( settingsChanged() ) , this , SLOT( slotSettingsChanged() ) );

	connect( KopeteMessageManagerFactory::factory(),
		SIGNAL( aboutToSend( KopeteMessage & ) ),
		SLOT( slotOutgoingMessage( KopeteMessage & ) ) );

	 last_color=0;
}

TextEffectPlugin::~TextEffectPlugin()
{
	delete m_config;
	pluginStatic_ = 0L;
}

TextEffectPlugin* TextEffectPlugin::plugin()
{
	return pluginStatic_ ;
}

TextEffectPlugin* TextEffectPlugin::pluginStatic_ = 0L;

void TextEffectPlugin::slotOutgoingMessage( KopeteMessage& msg )
{
	if(msg.direction() != KopeteMessage::Outbound)
		return;

	QStringList colors=m_config->colors();

	if(m_config->colorChar() || m_config->colorWords() || m_config->lamer() || m_config->waves() )
	{
		QString original=msg.plainBody();
		QString resultat;

		unsigned int c=0;
		bool wavein=false;

		for(unsigned int f=0;f<original.length();f++)
		{
			QChar x=original[f];
			if(f==0 || m_config->colorChar() || (m_config->colorWords() && x==' ' ))
			{
				if(f!=0)
					resultat+="";
				resultat+="colorRandom())
					c=rand()%colors.count();
				else
				{
					c++;
					if(c >= colors.count())
						c=0;
				}
				resultat+="\">";
			}
			switch (x.latin1())
			{
				case '>':
					resultat+=">";
					break;
				case '<':
					resultat+="<";
					break;
				case '&':
					resultat+="&";
					break;
				case '\n':
					resultat+="
";
				case 'a':
				case 'A':
					if(m_config->lamer())
					{
						resultat+="4";
						break;
					}
				case 'e':
				case 'E':
					if(m_config->lamer())
					{
						resultat+="3";
						break;
					}
				case 'i':
				case 'I':
					if(m_config->lamer())
					{
						resultat+="1";
						break;
					}
				case 'l':
				case 'L':
					if(m_config->lamer())
					{
						resultat+="|";
						break;
					}
				case 't':
				case 'T':
					if(m_config->lamer())
					{
						resultat+="7";
						break;
					}
				case 's':
				case 'S':
					if(m_config->lamer())
					{
						resultat+="5";
						break;
					}
				case 'o':
				case 'O':
					if(m_config->lamer())
					{
						resultat+="0";
						break;
					}
				default:
					if(m_config->waves())
					{
						resultat+= wavein ? x.lower() : x.upper();
						wavein=!wavein;
					}
					else
						resultat+=x;
					break;
			}
		}
		if( m_config->colorChar() || m_config->colorWords() )
			resultat+="";
		msg.setBody(resultat,KopeteMessage::RichText);
	}

	if(m_config->colorLines())
	{
		if(m_config->colorRandom())
		{
			last_color=rand()%colors.count();
		}
		else
		{
			last_color++;
			if(last_color >= colors.count())
				last_color=0;
		}

		msg.setFg(QColor (colors[last_color]));
	}
}

void TextEffectPlugin::slotSettingsChanged()
{
	m_config->load();
}

#include "texteffectplugin.moc"

<|endoftext|>


<commit_before>#pragma once

#include <map>
#include <mutex>
#include <string>
#include <unordered_map>

#include "blackhole/formatter/string.hpp"
#include "blackhole/frontend.hpp"
#include "blackhole/logger.hpp"
#include "blackhole/repository/config/defaults.hpp"
#include "blackhole/repository/config/log.hpp"
#include "blackhole/repository/factory/external.hpp"
#include "blackhole/sink/stream.hpp"

namespace blackhole {

class repository_t {
    external_factory_t factory;
    std::unordered_map<std::string, log_config_t> configs;

    mutable std::mutex mutex;

public:
    /*!
     * Default constructor.
     * After creation registeres string/stream frontend, which makes possible
     * to create logger with that frontend type.
     * Also adds trivial logger configuration.
     * @post: registered<sink::stream_t, formatter::string_t>() == true.
     * @post: create<T>("root") - should create valid logger.
     */
    repository_t();

    static repository_t& instance();

    /*!
     * Check whether some sink-formatter pair is registered with this
     * repository.
     * Registered sink-formatter pair composes into a frontend, which can be
     * potentially injected inside the logger. Trying to create a logger with
     * unregistered frontend results in exception.
     * @since: 0.3.
     */
    template<typename Sink, typename Formatter>
    bool registered() const;

    /*!
     * Alias for 'registered' method.
     * @see: repository_t::registered().
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Sink, typename Formatter>
    bool available() const BLACKHOLE_DEPRECATED("use 'registered' instead");

    /*!
     * Register sink-formatter pair (which is a frontend itself) with the
     * repository.
     * Registered frontends can be injected inside the logger while its
     * creation stage if the logger's configuration requires them.
     * @note: there is a better name - 'register'. Sadly, but it's C++'s
     *        keyword.
     * @post: registered<Sink, Formatter>() == true.
     * @todo: Test post condition.
     */
    template<typename Sink, typename Formatter>
    void registrate();

    /*!
     * Alias for 'registrate' method.
     * @see: repository_t::registrate.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Sink, typename Formatter>
    void configure() BLACKHOLE_DEPRECATED("use 'registrate' instead");

    /*!
     * Clear all registered frontend configurations as like as logger configs.
     * @post: registered<Sink, Formatter>() == false on any combinations of
     *        sinks and formatters.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    void clear() BLACKHOLE_DEPRECATED("there is no need for this method");

    /*!
     * Add generic logger configuration into the repository.
     * After that logger with name 'config.name' can be created using 'create'
     * method.
     * By default 'root' logger is registered with string-stream frontend.
     */
    void add_config(const log_config_t& config);

    /*!
     * Add several generic logger configurations into the repository.
     */
    void add_configs(const std::vector<log_config_t>& configs);

    /*!
     * Create logger from configuration named 'root', obviously.
     * To successfull logger creation its configuration named 'root' should be
     * added previously into the repository as like as its frontends must be
     * registered with.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Level>
    typename std::enable_if<
        std::is_enum<Level>::value,
        verbose_logger_t<Level>
    >::type
    root() const BLACKHOLE_DEPRECATED("use 'create<T>(\"root\")' instead");

    /*!
     * Create verbose logger with specified configuration name.
     * To successfull logger creation its configuration named 'root' should be
     * added previously into the repository as like as its frontends must be
     * registered with.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Level>
    typename std::enable_if<
        std::is_enum<Level>::value,
        verbose_logger_t<Level>
    >::type
    BLACKHOLE_DEPRECATED("use 'create<T>(name)' instead")
    create(const std::string& name) const;

    /*!
     * @since: 0.3.
     */
    template<class Logger>
    typename std::enable_if<
        std::is_base_of<logger_base_t, Logger>::value,
        Logger
    >::type
    create(const std::string& name) const {
        std::lock_guard<std::mutex> lock(mutex);

        const auto& frontends = configs.at(name).frontends;
        Logger logger;
        for (auto it = frontends.begin(); it != frontends.end(); ++it) {
            logger.add_frontend(factory.create(it->formatter, it->sink));
        }
        return logger;
    }
};

BLACKHOLE_API
repository_t::repository_t() {
    registrate<sink::stream_t, formatter::string_t>();
    add_config(repository::config::trivial());
}

BLACKHOLE_API
repository_t&
repository_t::instance() {
    static repository_t self;
    return self;
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
bool
repository_t::registered() const {
    std::lock_guard<std::mutex> lock(mutex);
    return factory.has<Sink, Formatter>();
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
bool
repository_t::available() const {
    return registered<Sink, Formatter>();
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
void
repository_t::registrate() {
    std::lock_guard<std::mutex> lock(mutex);
    external_inserter<Sink, Formatter>::insert(factory);
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
void
repository_t::configure() {
    registrate<Sink, Formatter>();
}

BLACKHOLE_API
void
repository_t::clear() {
    std::lock_guard<std::mutex> lock(mutex);
    factory.clear();
    configs.clear();
}

BLACKHOLE_API
void
repository_t::add_config(const log_config_t& config) {
    std::lock_guard<std::mutex> lock(mutex);
    configs[config.name] = config;
}

BLACKHOLE_API
void
repository_t::add_configs(const std::vector<log_config_t>& configs) {
    std::lock_guard<std::mutex> lock(mutex);
    for (auto it = configs.begin(); it != configs.end(); ++it) {
        this->configs[it->name] = *it;
    }
}

template<typename Level>
BLACKHOLE_API
typename std::enable_if<
    std::is_enum<Level>::value,
    verbose_logger_t<Level>
>::type
repository_t::root() const {
    return create<verbose_logger_t<Level>>("root");
}

template<typename Level>
BLACKHOLE_API
typename std::enable_if<
    std::is_enum<Level>::value,
    verbose_logger_t<Level>
>::type
repository_t::create(const std::string& name) const {
    return create<verbose_logger_t<Level>>(name);
}

} // namespace blackhole
<commit_msg>[Documentation] Repository class's methods are now fully documented.<commit_after>#pragma once

#include <map>
#include <mutex>
#include <string>
#include <unordered_map>

#include "blackhole/formatter/string.hpp"
#include "blackhole/frontend.hpp"
#include "blackhole/logger.hpp"
#include "blackhole/repository/config/defaults.hpp"
#include "blackhole/repository/config/log.hpp"
#include "blackhole/repository/factory/external.hpp"
#include "blackhole/sink/stream.hpp"

namespace blackhole {

class repository_t {
    external_factory_t factory;
    std::unordered_map<std::string, log_config_t> configs;

    mutable std::mutex mutex;

public:
    /*!
     * Default constructor.
     * After creation registeres string/stream frontend, which makes possible
     * to create logger with that frontend type.
     * Also adds trivial logger configuration.
     * @post: registered<sink::stream_t, formatter::string_t>() == true.
     * @post: create<T>("root") - should create valid logger.
     */
    repository_t();

    static repository_t& instance();

    /*!
     * Check whether some sink-formatter pair is registered with this
     * repository.
     * Registered sink-formatter pair composes into a frontend, which can be
     * potentially injected inside the logger. Trying to create a logger with
     * unregistered frontend results in exception.
     * @since: 0.3.
     */
    template<typename Sink, typename Formatter>
    bool registered() const;

    /*!
     * Alias for 'registered' method.
     * @see: repository_t::registered().
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Sink, typename Formatter>
    bool available() const BLACKHOLE_DEPRECATED("use 'registered' instead");

    /*!
     * Register sink-formatter pair (which is a frontend itself) with the
     * repository.
     * Registered frontends can be injected inside the logger while its
     * creation stage if the logger's configuration requires them.
     * @note: there is a better name - 'register'. Sadly, but it's C++'s
     *        keyword.
     * @post: registered<Sink, Formatter>() == true.
     * @todo: Test post condition.
     */
    template<typename Sink, typename Formatter>
    void registrate();

    /*!
     * Alias for 'registrate' method.
     * @see: repository_t::registrate.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Sink, typename Formatter>
    void configure() BLACKHOLE_DEPRECATED("use 'registrate' instead");

    /*!
     * Clear all registered frontend configurations as like as logger configs.
     * @post: registered<Sink, Formatter>() == false on any combinations of
     *        sinks and formatters.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    void clear() BLACKHOLE_DEPRECATED("there is no need for this method");

    /*!
     * Add generic logger configuration into the repository.
     * After that logger with name 'config.name' can be created using 'create'
     * method.
     * By default 'root' logger is registered with string-stream frontend.
     */
    void add_config(const log_config_t& config);

    /*!
     * Add several generic logger configurations into the repository.
     */
    void add_configs(const std::vector<log_config_t>& configs);

    /*!
     * Create logger from configuration named 'root', obviously.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Level>
    typename std::enable_if<
        std::is_enum<Level>::value,
        verbose_logger_t<Level>
    >::type
    root() const BLACKHOLE_DEPRECATED("use 'create<T>(\"root\")' instead");

    /*!
     * Create verbose logger with specified configuration name.
     * @deprecated[soft]: since 0.3.
     * @deprecated[hard]: will be removed since 0.4.
     */
    template<typename Level>
    typename std::enable_if<
        std::is_enum<Level>::value,
        verbose_logger_t<Level>
    >::type
    BLACKHOLE_DEPRECATED("use 'create<T>(name)' instead")
    create(const std::string& name) const;

    /*!
     * Create typed logger with specified configuration name.
     * To successfull logger creation its configuration named 'root' should be
     * added previously into the repository as like as its frontends must be
     * registered with.
     * @since: 0.3.
     */
    template<class Logger>
    typename std::enable_if<
        std::is_base_of<logger_base_t, Logger>::value,
        Logger
    >::type
    create(const std::string& name) const;
};

BLACKHOLE_API
repository_t::repository_t() {
    registrate<sink::stream_t, formatter::string_t>();
    add_config(repository::config::trivial());
}

BLACKHOLE_API
repository_t&
repository_t::instance() {
    static repository_t self;
    return self;
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
bool
repository_t::registered() const {
    std::lock_guard<std::mutex> lock(mutex);
    return factory.has<Sink, Formatter>();
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
bool
repository_t::available() const {
    return registered<Sink, Formatter>();
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
void
repository_t::registrate() {
    std::lock_guard<std::mutex> lock(mutex);
    external_inserter<Sink, Formatter>::insert(factory);
}

template<typename Sink, typename Formatter>
BLACKHOLE_API
void
repository_t::configure() {
    registrate<Sink, Formatter>();
}

BLACKHOLE_API
void
repository_t::clear() {
    std::lock_guard<std::mutex> lock(mutex);
    factory.clear();
    configs.clear();
}

BLACKHOLE_API
void
repository_t::add_config(const log_config_t& config) {
    std::lock_guard<std::mutex> lock(mutex);
    configs[config.name] = config;
}

BLACKHOLE_API
void
repository_t::add_configs(const std::vector<log_config_t>& configs) {
    std::lock_guard<std::mutex> lock(mutex);
    for (auto it = configs.begin(); it != configs.end(); ++it) {
        this->configs[it->name] = *it;
    }
}

template<typename Level>
BLACKHOLE_API
typename std::enable_if<
    std::is_enum<Level>::value,
    verbose_logger_t<Level>
>::type
repository_t::root() const {
    return create<verbose_logger_t<Level>>("root");
}

template<typename Level>
BLACKHOLE_API
typename std::enable_if<
    std::is_enum<Level>::value,
    verbose_logger_t<Level>
>::type
repository_t::create(const std::string& name) const {
    return create<verbose_logger_t<Level>>(name);
}

template<class Logger>
BLACKHOLE_API
typename std::enable_if<
    std::is_base_of<logger_base_t, Logger>::value,
    Logger
>::type
repository_t::create(const std::string& name) const {
    std::lock_guard<std::mutex> lock(mutex);

    const auto& frontends = configs.at(name).frontends;
    Logger logger;
    for (auto it = frontends.begin(); it != frontends.end(); ++it) {
        logger.add_frontend(factory.create(it->formatter, it->sink));
    }
    return logger;
}

} // namespace blackhole
<|endoftext|>


<commit_before>#pragma once

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/version.hpp>

#include "blackhole/error.hpp"

namespace blackhole {

namespace sink {

class boost_backend_t {
    boost::filesystem::path m_path;
    boost::filesystem::ofstream m_file;
public:
    boost_backend_t(const std::string& path) :
        m_path(path)
    {
    }

    bool opened() const {
        return m_file.is_open();
    }

    bool open() {
        m_file.open(m_path, std::ios_base::out | std::ios_base::app);
        return m_file.is_open();
    }

    std::string path() const {
#if BOOST_VERSION >= 104600
        return m_path.filename().string();
#else
        return m_path.filename();
#endif
    }

    void write(const std::string& message) {
        m_file.write(message.data(), static_cast<std::streamsize>(message.size()));
        m_file.put('\n');
        //!@todo: Make auto_flush flag.
        m_file.flush();
    }
};

template<class Backend = boost_backend_t>
class file_t {
    Backend m_backend;
public:
    file_t(const std::string& path) :
        m_backend(path)
    {
    }

    void consume(const std::string& message) {
        //!@todo: if (m_backend.need_rotate(message.size()) m_backend.rotate();

        if (!m_backend.opened()) {
            //!@todo: create directory if not exists
            if (!m_backend.open()) {
                throw error_t("failed to open file '%s' for writing", m_backend.path());
            }
        }
        m_backend.write(message);
    }

    Backend& backend() {
        return m_backend;
    }
};

} // namespace sink

} // namespace blackhole
<commit_msg>Additional tasks added.<commit_after>#pragma once

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/version.hpp>

#include "blackhole/error.hpp"

namespace blackhole {

namespace sink {

class boost_backend_t {
    boost::filesystem::path m_path;
    boost::filesystem::ofstream m_file;
public:
    boost_backend_t(const std::string& path) :
        m_path(path)
    {
    }

    bool opened() const {
        return m_file.is_open();
    }

    bool open() {
        m_file.open(m_path, std::ios_base::out | std::ios_base::app);
        return m_file.is_open();
    }

    std::string path() const {
#if BOOST_VERSION >= 104600
        return m_path.filename().string();
#else
        return m_path.filename();
#endif
    }

    void write(const std::string& message) {
        m_file.write(message.data(), static_cast<std::streamsize>(message.size()));
        m_file.put('\n');
        //!@todo: Make auto_flush flag.
        m_file.flush();
    }
};

template<class Backend = boost_backend_t>
class file_t {
    Backend m_backend;
public:
    file_t(const std::string& path) :
        m_backend(path)
    {
    }

    void consume(const std::string& message) {
        //!@todo: Make file rotation.
        //!@todo: Make file naming by pattern.

        if (!m_backend.opened()) {
            //!@todo: Create directory if not exists.
            if (!m_backend.open()) {
                throw error_t("failed to open file '%s' for writing", m_backend.path());
            }
        }
        m_backend.write(message);
    }

    Backend& backend() {
        return m_backend;
    }
};

} // namespace sink

} // namespace blackhole
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX600 グループ・ペリフェラル
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ペリフェラル種別
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	enum class peripheral : uint16_t {

		DMAC0,	///< DMA コントローラ・チャネル０
		DMAC1,	///< DMA コントローラ・チャネル１
		DMAC2,	///< DMA コントローラ・チャネル２
		DMAC3,	///< DMA コントローラ・チャネル３
		DMAC4,	///< DMA コントローラ・チャネル４
		DMAC5,	///< DMA コントローラ・チャネル５
		DMAC6,	///< DMA コントローラ・チャネル６
		DMAC7,	///< DMA コントローラ・チャネル７

		MTU0,	///< マルチファンクションタイマパルスユニット０
		MTU1,	///< マルチファンクションタイマパルスユニット１
		MTU2,	///< マルチファンクションタイマパルスユニット２
		MTU3,	///< マルチファンクションタイマパルスユニット３
		MTU4,	///< マルチファンクションタイマパルスユニット４
		MTU5,	///< マルチファンクションタイマパルスユニット５
		MTU6,	///< マルチファンクションタイマパルスユニット６
		MTU7,	///< マルチファンクションタイマパルスユニット７

		TMR0,	///< 8 ビットタイマ０
		TMR1,	///< 8 ビットタイマ１
		TMR2,	///< 8 ビットタイマ２
		TMR3,	///< 8 ビットタイマ３

		CMT0,	///< コンペアマッチタイマ（CMT）
		CMT1,	///< コンペアマッチタイマ（CMT）
		CMT2,	///< コンペアマッチタイマ（CMT）
		CMT3,	///< コンペアマッチタイマ（CMT）

		TPU0,	///< 16 ビットタイマパルスユニット０
		TPU1,	///< 16 ビットタイマパルスユニット１
		TPU2,	///< 16 ビットタイマパルスユニット２
		TPU3,	///< 16 ビットタイマパルスユニット３
		TPU4,	///< 16 ビットタイマパルスユニット４
		TPU5,	///< 16 ビットタイマパルスユニット５

		DTC,		///< データトランスファコントローラ

		ETHERC0,	///< Ethernet 0 (PHY RMII)
		ETHERC1,	///< Ethernet 1 (PHY RMII)
		PTPETHERC,	///< PTP Ethernet

		ETHERCA,	///< Ethernet 0 (PHY RMII)カスタムポート接続

		EDMAC0,		///< Ethernet DMA 0
		EDMAC1,		///< Ethernet DMA 1
		PTPEDMAC,	///< PTP Ethernet DMA

		SCI0,		///< シリアルコミュニケーションインタフェース (P20:TXD0, P21:RXD0)
		SCI1,		///< シリアルコミュニケーションインタフェース (PF0:TXD1, PF2:RXD1)
		SCI2,		///< シリアルコミュニケーションインタフェース (P13:TXD2, P12:RXD2)
		SCI3,		///< シリアルコミュニケーションインタフェース (P23:TXD3, P25:RXD3)
		SCI4,		///< シリアルコミュニケーションインタフェース (PB1:TXD4, PB0:RXD4)
		SCI5,		///< シリアルコミュニケーションインタフェース (PA4:TXD5, PA2:RXD5)
		SCI6,		///< シリアルコミュニケーションインタフェース (P00:TXD6, P01:RXD6)
		SCI7,		///< シリアルコミュニケーションインタフェース (P90:TXD7, P92:RXD7)
#if defined(SIG_RX64M) || defined(SIG_RX71M)
		SCIF8,		///< FIFO 内臓シリアルコミュニケーションインターフェース
		SCIF9,		///< FIFO 内臓シリアルコミュニケーションインターフェース
		SCIF10,		///< FIFO 内臓シリアルコミュニケーションインターフェース
		SCIF11,		///< FIFO 内臓シリアルコミュニケーションインターフェース
#elif defined(SIG_RX65N)
		SCI8,		///< シリアルコミュニケーションインターフェース
		SCI9,		///< シリアルコミュニケーションインターフェース
		SCI10,		///< シリアルコミュニケーションインターフェース
		SCI11,		///< シリアルコミュニケーションインターフェース
#endif
		SCI12,		///< シリアルコミュニケーションインタフェース

		RIIC0,		///< I 2 C バスインタフェース（RIICa）
		RIIC2,		///< I 2 C バスインタフェース（RIICa）

		CAN0,		///< CAN インタフェース（CAN0）
		CAN1,		///< CAN インタフェース（CAN1）
#if defined(SIG_RX64M) || defined(SIG_RX71M)
		CAN2,		///< CAN インタフェース（CAN2）
#endif
#if defined(SIG_RX65N)
		RSPI0,		///< シリアルペリフェラルインタフェース（RSPI0）
		RSPI1,		///< シリアルペリフェラルインタフェース（RSPI1）
#else
		RSPI,		///< シリアルペリフェラルインタフェース（RSPIa）
#endif
#ifdef SIG_RX71M
		RSPI2,		///< シリアルペリフェラルインタフェース（RSPIb）
#endif
		QSPI,		///< クワッドシリアルペリフェラルインタフェース（QSPI）

		SSI0,		///< シリアルサウンドインタフェース（SSI）
		SSI1,		///< シリアルサウンドインタフェース（SSI）

		SRC,		///< サンプリングレートコンバータ（SRC）

		SDHI,		///< SD ホストインタフェース（SDHI）

		S12AD,		///< 12 ビット A/D コンバータ（S12ADC）
		S12AD1,		///< 12 ビット A/D コンバータ（S12ADC）

		R12DA,		///< 12 ビット D/A コンバータ（R12DA）

		ECCRAM,		///< ECC RAM (32K)
		STBRAM,		///< Standby RAM (8K)

		// 仮の仕様
		IRQ0,
		IRQ1,
		IRQ2,
		IRQ3,
		IRQ4,
		IRQ5,
		IRQ6,
		IRQ7,

#ifdef SIG_RX65N
		GLCDC,		///< グラフィック LCD コントローラ (GLCDC)
		DRW2D,		///< 2D 描画エンジン (DRW2D)
#endif
	};
}
<commit_msg>update: cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX600 グループ・ペリフェラル
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ペリフェラル種別
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	enum class peripheral : uint16_t {

		DMAC0,	///< DMA コントローラ・チャネル０
		DMAC1,	///< DMA コントローラ・チャネル１
		DMAC2,	///< DMA コントローラ・チャネル２
		DMAC3,	///< DMA コントローラ・チャネル３
		DMAC4,	///< DMA コントローラ・チャネル４
		DMAC5,	///< DMA コントローラ・チャネル５
		DMAC6,	///< DMA コントローラ・チャネル６
		DMAC7,	///< DMA コントローラ・チャネル７

		MTU0,	///< マルチファンクションタイマパルスユニット０
		MTU1,	///< マルチファンクションタイマパルスユニット１
		MTU2,	///< マルチファンクションタイマパルスユニット２
		MTU3,	///< マルチファンクションタイマパルスユニット３
		MTU4,	///< マルチファンクションタイマパルスユニット４
		MTU5,	///< マルチファンクションタイマパルスユニット５
		MTU6,	///< マルチファンクションタイマパルスユニット６
		MTU7,	///< マルチファンクションタイマパルスユニット７

		TMR0,	///< 8 ビットタイマ０
		TMR1,	///< 8 ビットタイマ１
		TMR2,	///< 8 ビットタイマ２
		TMR3,	///< 8 ビットタイマ３

		CMT0,	///< コンペアマッチタイマ（CMT）
		CMT1,	///< コンペアマッチタイマ（CMT）
		CMT2,	///< コンペアマッチタイマ（CMT）
		CMT3,	///< コンペアマッチタイマ（CMT）

		TPU0,	///< 16 ビットタイマパルスユニット０
		TPU1,	///< 16 ビットタイマパルスユニット１
		TPU2,	///< 16 ビットタイマパルスユニット２
		TPU3,	///< 16 ビットタイマパルスユニット３
		TPU4,	///< 16 ビットタイマパルスユニット４
		TPU5,	///< 16 ビットタイマパルスユニット５

		DTC,		///< データトランスファコントローラ

		ETHERC0,	///< Ethernet 0 (PHY RMII)
		ETHERC1,	///< Ethernet 1 (PHY RMII)
		PTPETHERC,	///< PTP Ethernet

		ETHERCA,	///< Ethernet 0 (PHY RMII)カスタムポート接続

		EDMAC0,		///< Ethernet DMA 0
		EDMAC1,		///< Ethernet DMA 1
		PTPEDMAC,	///< PTP Ethernet DMA

		SCI0,		///< シリアルコミュニケーションインタフェース (P20:TXD0, P21:RXD0)
		SCI1,		///< シリアルコミュニケーションインタフェース (PF0:TXD1, PF2:RXD1)
		SCI2,		///< シリアルコミュニケーションインタフェース (P13:TXD2, P12:RXD2)
		SCI3,		///< シリアルコミュニケーションインタフェース (P23:TXD3, P25:RXD3)
		SCI4,		///< シリアルコミュニケーションインタフェース (PB1:TXD4, PB0:RXD4)
		SCI5,		///< シリアルコミュニケーションインタフェース (PA4:TXD5, PA2:RXD5)
		SCI6,		///< シリアルコミュニケーションインタフェース (P00:TXD6, P01:RXD6)
		SCI7,		///< シリアルコミュニケーションインタフェース (P90:TXD7, P92:RXD7)
#if defined(SIG_RX64M) || defined(SIG_RX71M)
		SCIF8,		///< FIFO 内臓シリアルコミュニケーションインターフェース
		SCIF9,		///< FIFO 内臓シリアルコミュニケーションインターフェース
		SCIF10,		///< FIFO 内臓シリアルコミュニケーションインターフェース
		SCIF11,		///< FIFO 内臓シリアルコミュニケーションインターフェース
#elif defined(SIG_RX65N)
		SCI8,		///< シリアルコミュニケーションインターフェース
		SCI9,		///< シリアルコミュニケーションインターフェース
		SCI10,		///< シリアルコミュニケーションインターフェース
		SCI11,		///< シリアルコミュニケーションインターフェース
#endif
		SCI12,		///< シリアルコミュニケーションインタフェース

		RIIC0,		///< I 2 C バスインタフェース（RIICa）
		RIIC2,		///< I 2 C バスインタフェース（RIICa）

		CAN0,		///< CAN インタフェース（CAN0）
		CAN1,		///< CAN インタフェース（CAN1）
#if defined(SIG_RX64M) || defined(SIG_RX71M)
		CAN2,		///< CAN インタフェース（CAN2）
#endif
#if defined(SIG_RX65N)
		RSPI0,		///< シリアルペリフェラルインタフェース（RSPI0）
		RSPI1,		///< シリアルペリフェラルインタフェース（RSPI1）
#else
		RSPI,		///< シリアルペリフェラルインタフェース（RSPIa）
#endif
#ifdef SIG_RX71M
		RSPI2,		///< シリアルペリフェラルインタフェース（RSPIb）
#endif
		QSPI,		///< クワッドシリアルペリフェラルインタフェース（QSPI）

		SSI0,		///< シリアルサウンドインタフェース（SSI）
		SSI1,		///< シリアルサウンドインタフェース（SSI）

		SRC,		///< サンプリングレートコンバータ（SRC）

		SDHI,		///< SD ホストインタフェース（SDHI）

		S12AD,		///< 12 ビット A/D コンバータ（S12ADC）
		S12AD1,		///< 12 ビット A/D コンバータ（S12ADC）

		R12DA,		///< 12 ビット D/A コンバータ（R12DA）

		ECCRAM,		///< ECC RAM (32K)
		STBRAM,		///< Standby RAM (8K)

		// 仮の仕様
		IRQ0,
		IRQ1,
		IRQ2,
		IRQ3,
		IRQ4,
		IRQ5,
		IRQ6,
		IRQ7,

#ifdef SIG_RX65N
		GLCDC,		///< グラフィック LCD コントローラ (GLCDC)
		DRW2D,		///< 2D 描画エンジン (DRW2D)
#endif

		ICU,		///< グループ割り込みペリフェラル
	};
}
<|endoftext|>


<commit_before>/*  XMMS2 - X Music Multiplexer System
 *  Copyright (C) 2003-2008 XMMS2 Team
 *
 *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 */

/**
  * @file gme decoder.
  * @url http://wiki.xmms2.xmms.se/index.php/Notes_from_developing_an_xform_plugin
  */

#include <glib.h>
#include <stdlib.h>

#include "xmms/xmms_xformplugin.h"
#include "xmms/xmms_sample.h"
#include "xmms/xmms_log.h"
#include "xmms/xmms_medialib.h"
#include "gme/gme.h"

#define GME_DEFAULT_SAMPLE_RATE 44100
#define GME_DEFAULT_SONG_LENGTH 300
#define GME_DEFAULT_SONG_LOOPS 2

extern "C" {

/*
 * Persistent data
 *
 */
typedef struct xmms_gme_data_St {
	Music_Emu *emu; /* An emulation instance for the GME library */
	int samplerate; /* The sample rate, set by the user */
} xmms_gme_data_t;

/*
 * Function prototypes
 */

static gboolean xmms_gme_plugin_setup (xmms_xform_plugin_t *xform_plugin);
static gint xmms_gme_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err);
static gboolean xmms_gme_init (xmms_xform_t *decoder);
static void xmms_gme_destroy (xmms_xform_t *decoder);
static gint64 xmms_gme_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err);

/*
 * Plugin header
 */

XMMS_XFORM_PLUGIN ("gme",
                   "Game Music decoder", XMMS_VERSION,
                   "Game Music Emulator music decoder",
                   xmms_gme_plugin_setup);

static gboolean
xmms_gme_plugin_setup (xmms_xform_plugin_t *xform_plugin)
{
	xmms_xform_methods_t methods;

	XMMS_XFORM_METHODS_INIT (methods);
	methods.init = xmms_gme_init;
	methods.destroy = xmms_gme_destroy;
	methods.read = xmms_gme_read;
	methods.seek = xmms_gme_seek;

	xmms_xform_plugin_methods_set (xform_plugin, &methods);

	xmms_xform_plugin_config_property_register (xform_plugin, "loops", G_STRINGIFY (GME_DEFAULT_SONG_LOOPS), NULL, NULL);
	xmms_xform_plugin_config_property_register (xform_plugin, "maxlength", G_STRINGIFY (GME_DEFAULT_SONG_LENGTH), NULL, NULL);
	xmms_xform_plugin_config_property_register (xform_plugin, "samplerate", G_STRINGIFY (GME_DEFAULT_SAMPLE_RATE), NULL, NULL);

	/* todo: add other mime types */
	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-spc",
	                              NULL);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-nsf",
	                              NULL);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-gbs",
	                              NULL);

	/* todo: add other magic */
	xmms_magic_add ("SPC700 save state",
	                "application/x-spc",
	                "0 string SNES-SPC700 Sound File Data",
	                NULL);

	xmms_magic_add ("NSF file",
	                "application/x-nsf",
	                "0 string NESM",
	                NULL);

	xmms_magic_add ("GBS file",
	                "application/x-gbs",
	                "0 string GBS",
	                NULL);

	/* todo: add other file extensions */
	xmms_magic_extension_add ("application/x-spc", "*.spc");
	xmms_magic_extension_add ("application/x-nsf", "*.nsf");
	xmms_magic_extension_add ("application/x-gbs", "*.gbs");

	return TRUE;
}

static gboolean
xmms_gme_init (xmms_xform_t *xform)
{
	xmms_gme_data_t *data;
	gme_err_t init_error;
	GString *file_contents; /* The raw data from the file. */
	track_info_t metadata;
	xmms_config_property_t *val;
	int loops;
	int maxlength;
	const char *subtune_str;
	int subtune = 0;
	long fadelen = -1;
	int samplerate;

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_gme_data_t, 1);

	xmms_xform_private_data_set (xform, data);

	val = xmms_xform_config_lookup (xform, "samplerate");
	samplerate = xmms_config_property_get_int (val);
	if (samplerate < 1)
		samplerate = GME_DEFAULT_SAMPLE_RATE;
	data->samplerate = samplerate;

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm", /* PCM samples */
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16, /* 16-bit signed */
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             2, /* stereo */
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             samplerate,
	                             XMMS_STREAM_TYPE_END);

	file_contents = g_string_new ("");

	for (;;) {
		xmms_error_t error;
		gchar buf[4096];
		gint ret;

		ret = xmms_xform_read (xform, buf, sizeof (buf), &error);
		if (ret == -1) {
			XMMS_DBG ("Error reading emulated music data");
			return FALSE;
		}
		if (ret == 0) {
			break;
		}
		g_string_append_len (file_contents, buf, ret);
	}

	init_error = gme_open_data (file_contents->str, file_contents->len, &data->emu, samplerate);

	if (init_error) {
		XMMS_DBG ("gme_open_data returned an error: %s", init_error);
		return FALSE;
	}

	if (xmms_xform_metadata_get_str (xform, "subtune", &subtune_str)) {
		subtune = strtol (subtune_str, NULL, 10);
		XMMS_DBG ("Setting subtune to %d", subtune);
		if ((subtune < 0 || subtune > gme_track_count (data->emu))) {
			XMMS_DBG ("Invalid subtune index");
			return FALSE;
		}
	} else {
		xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SUBTUNES, gme_track_count (data->emu));
	}

	/*
	 *  Get metadata here
	 */
	init_error = gme_track_info (data->emu, &metadata, subtune);
	if (init_error) {
		XMMS_DBG ("Couldn't get GME track info: %s", init_error);
		init_error = "";
	} else {
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata.song);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata.author);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, metadata.game);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata.comment);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR, metadata.copyright);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE, metadata.system);  /* I mapped genre to the system type */

		val = xmms_xform_config_lookup (xform, "loops");
		loops = xmms_config_property_get_int (val);

		XMMS_DBG ("intro_length = %ld, loops = %d, loop_length = %ld", metadata.intro_length, loops, metadata.loop_length);

		if (metadata.intro_length > 0) {
			if ((loops > 0) && (metadata.loop_length > 0)) {
				fadelen = metadata.intro_length + loops * metadata.loop_length;
				XMMS_DBG ("fadelen now = %ld", fadelen);
			} else {
				fadelen = metadata.length;
				XMMS_DBG ("fadelen now = %ld", fadelen);
			}
		}
	}

	val = xmms_xform_config_lookup (xform, "maxlength");
	maxlength = xmms_config_property_get_int (val);

	XMMS_DBG ("maxlength = %d seconds", maxlength);

	if (maxlength > 0 && (fadelen < 0 || (maxlength * 1000L < fadelen))) {
		fadelen = maxlength * 1000L;
		XMMS_DBG ("fadelen now = %ld", fadelen);
	}

	XMMS_DBG ("gme.fadelen = %ld", fadelen);

	init_error = gme_start_track (data->emu, subtune);
	if (init_error) {
		XMMS_DBG ("gme_start_track returned an error: %s", init_error);
		return FALSE;
	}

	if (fadelen > 0) {
		XMMS_DBG ("Setting song length and fade length...");
		xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, fadelen);
		gme_set_fade (data->emu, fadelen);
	}

	g_string_free (file_contents, TRUE);

	return TRUE;
}

static void
xmms_gme_destroy (xmms_xform_t *xform)
{
	xmms_gme_data_t *data;

	g_return_if_fail (xform);

	data = (xmms_gme_data_t *)xmms_xform_private_data_get (xform);
	g_return_if_fail (data);

	if (data->emu)
		gme_delete (data->emu);

	g_free (data);

}

/* Read some data */
static gint
xmms_gme_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
{
	xmms_gme_data_t *data;
	gme_err_t play_error;

	g_return_val_if_fail (xform, -1);

	data = (xmms_gme_data_t *)xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, -1);

	if (gme_track_ended (data->emu))
		return 0;

	play_error = gme_play (data->emu, len/2, (short int *)buf);
	if (play_error) {
		XMMS_DBG ("gme_play returned an error: %s", play_error);
		xmms_error_set (err, XMMS_ERROR_GENERIC, play_error);
		return -1;
	}

	return len;
}

static gint64
xmms_gme_seek (xmms_xform_t *xform, gint64 samples,
               xmms_xform_seek_mode_t whence, xmms_error_t *err)
{
	xmms_gme_data_t *data;
	gint64 target_time;
	gint duration;
	int samplerate;

	g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1);
	g_return_val_if_fail (xform, -1);

	data = (xmms_gme_data_t *) xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, -1);

	samplerate = data->samplerate;

	if (samples < 0) {
		xmms_error_set (err, XMMS_ERROR_INVAL,
		                "Trying to seek before start of stream");
		return -1;
	}

	target_time = (samples / samplerate) * 1000;
	xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, &duration);

	if (target_time > duration) {
		xmms_error_set (err, XMMS_ERROR_INVAL,
		                "Trying to seek past end of stream");
		return -1;
	}

	gme_seek (data->emu, target_time);

	return (gme_tell (data->emu) / 1000) * samplerate;
}

}
<commit_msg>OTHER: Added GYM magic to GME plugin<commit_after>/*  XMMS2 - X Music Multiplexer System
 *  Copyright (C) 2003-2008 XMMS2 Team
 *
 *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 */

/**
  * @file gme decoder.
  * @url http://wiki.xmms2.xmms.se/index.php/Notes_from_developing_an_xform_plugin
  */

#include <glib.h>
#include <stdlib.h>

#include "xmms/xmms_xformplugin.h"
#include "xmms/xmms_sample.h"
#include "xmms/xmms_log.h"
#include "xmms/xmms_medialib.h"
#include "gme/gme.h"

#define GME_DEFAULT_SAMPLE_RATE 44100
#define GME_DEFAULT_SONG_LENGTH 300
#define GME_DEFAULT_SONG_LOOPS 2

extern "C" {

/*
 * Persistent data
 *
 */
typedef struct xmms_gme_data_St {
	Music_Emu *emu; /* An emulation instance for the GME library */
	int samplerate; /* The sample rate, set by the user */
} xmms_gme_data_t;

/*
 * Function prototypes
 */

static gboolean xmms_gme_plugin_setup (xmms_xform_plugin_t *xform_plugin);
static gint xmms_gme_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err);
static gboolean xmms_gme_init (xmms_xform_t *decoder);
static void xmms_gme_destroy (xmms_xform_t *decoder);
static gint64 xmms_gme_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err);

/*
 * Plugin header
 */

XMMS_XFORM_PLUGIN ("gme",
                   "Game Music decoder", XMMS_VERSION,
                   "Game Music Emulator music decoder",
                   xmms_gme_plugin_setup);

static gboolean
xmms_gme_plugin_setup (xmms_xform_plugin_t *xform_plugin)
{
	xmms_xform_methods_t methods;

	XMMS_XFORM_METHODS_INIT (methods);
	methods.init = xmms_gme_init;
	methods.destroy = xmms_gme_destroy;
	methods.read = xmms_gme_read;
	methods.seek = xmms_gme_seek;

	xmms_xform_plugin_methods_set (xform_plugin, &methods);

	xmms_xform_plugin_config_property_register (xform_plugin, "loops", G_STRINGIFY (GME_DEFAULT_SONG_LOOPS), NULL, NULL);
	xmms_xform_plugin_config_property_register (xform_plugin, "maxlength", G_STRINGIFY (GME_DEFAULT_SONG_LENGTH), NULL, NULL);
	xmms_xform_plugin_config_property_register (xform_plugin, "samplerate", G_STRINGIFY (GME_DEFAULT_SAMPLE_RATE), NULL, NULL);

	/* todo: add other mime types */
	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-spc",
	                              NULL);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-nsf",
	                              NULL);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-gbs",
	                              NULL);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "application/x-gym",
	                              NULL);

	/* todo: add other magic */
	xmms_magic_add ("SPC700 save state",
	                "application/x-spc",
	                "0 string SNES-SPC700 Sound File Data",
	                NULL);

	xmms_magic_add ("NSF file",
	                "application/x-nsf",
	                "0 string NESM",
	                NULL);

	xmms_magic_add ("GBS file",
	                "application/x-gbs",
	                "0 string GBS",
	                NULL);

	xmms_magic_add ("GYM file",
	                "application/x-gym",
	                "0 string GYMX",
	                NULL);

	/* todo: add other file extensions */
	xmms_magic_extension_add ("application/x-spc", "*.spc");
	xmms_magic_extension_add ("application/x-nsf", "*.nsf");
	xmms_magic_extension_add ("application/x-gbs", "*.gbs");
	xmms_magic_extension_add ("application/x-gym", "*.gym");

	return TRUE;
}

static gboolean
xmms_gme_init (xmms_xform_t *xform)
{
	xmms_gme_data_t *data;
	gme_err_t init_error;
	GString *file_contents; /* The raw data from the file. */
	track_info_t metadata;
	xmms_config_property_t *val;
	int loops;
	int maxlength;
	const char *subtune_str;
	int subtune = 0;
	long fadelen = -1;
	int samplerate;

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_gme_data_t, 1);

	xmms_xform_private_data_set (xform, data);

	val = xmms_xform_config_lookup (xform, "samplerate");
	samplerate = xmms_config_property_get_int (val);
	if (samplerate < 1)
		samplerate = GME_DEFAULT_SAMPLE_RATE;
	data->samplerate = samplerate;

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm", /* PCM samples */
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16, /* 16-bit signed */
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             2, /* stereo */
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             samplerate,
	                             XMMS_STREAM_TYPE_END);

	file_contents = g_string_new ("");

	for (;;) {
		xmms_error_t error;
		gchar buf[4096];
		gint ret;

		ret = xmms_xform_read (xform, buf, sizeof (buf), &error);
		if (ret == -1) {
			XMMS_DBG ("Error reading emulated music data");
			return FALSE;
		}
		if (ret == 0) {
			break;
		}
		g_string_append_len (file_contents, buf, ret);
	}

	init_error = gme_open_data (file_contents->str, file_contents->len, &data->emu, samplerate);

	if (init_error) {
		XMMS_DBG ("gme_open_data returned an error: %s", init_error);
		return FALSE;
	}

	if (xmms_xform_metadata_get_str (xform, "subtune", &subtune_str)) {
		subtune = strtol (subtune_str, NULL, 10);
		XMMS_DBG ("Setting subtune to %d", subtune);
		if ((subtune < 0 || subtune > gme_track_count (data->emu))) {
			XMMS_DBG ("Invalid subtune index");
			return FALSE;
		}
	} else {
		xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SUBTUNES, gme_track_count (data->emu));
	}

	/*
	 *  Get metadata here
	 */
	init_error = gme_track_info (data->emu, &metadata, subtune);
	if (init_error) {
		XMMS_DBG ("Couldn't get GME track info: %s", init_error);
		init_error = "";
	} else {
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata.song);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata.author);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, metadata.game);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata.comment);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR, metadata.copyright);
		xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE, metadata.system);  /* I mapped genre to the system type */

		val = xmms_xform_config_lookup (xform, "loops");
		loops = xmms_config_property_get_int (val);

		XMMS_DBG ("intro_length = %ld, loops = %d, loop_length = %ld", metadata.intro_length, loops, metadata.loop_length);

		if (metadata.intro_length > 0) {
			if ((loops > 0) && (metadata.loop_length > 0)) {
				fadelen = metadata.intro_length + loops * metadata.loop_length;
				XMMS_DBG ("fadelen now = %ld", fadelen);
			} else {
				fadelen = metadata.length;
				XMMS_DBG ("fadelen now = %ld", fadelen);
			}
		}
	}

	val = xmms_xform_config_lookup (xform, "maxlength");
	maxlength = xmms_config_property_get_int (val);

	XMMS_DBG ("maxlength = %d seconds", maxlength);

	if (maxlength > 0 && (fadelen < 0 || (maxlength * 1000L < fadelen))) {
		fadelen = maxlength * 1000L;
		XMMS_DBG ("fadelen now = %ld", fadelen);
	}

	XMMS_DBG ("gme.fadelen = %ld", fadelen);

	init_error = gme_start_track (data->emu, subtune);
	if (init_error) {
		XMMS_DBG ("gme_start_track returned an error: %s", init_error);
		return FALSE;
	}

	if (fadelen > 0) {
		XMMS_DBG ("Setting song length and fade length...");
		xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, fadelen);
		gme_set_fade (data->emu, fadelen);
	}

	g_string_free (file_contents, TRUE);

	return TRUE;
}

static void
xmms_gme_destroy (xmms_xform_t *xform)
{
	xmms_gme_data_t *data;

	g_return_if_fail (xform);

	data = (xmms_gme_data_t *)xmms_xform_private_data_get (xform);
	g_return_if_fail (data);

	if (data->emu)
		gme_delete (data->emu);

	g_free (data);

}

/* Read some data */
static gint
xmms_gme_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
{
	xmms_gme_data_t *data;
	gme_err_t play_error;

	g_return_val_if_fail (xform, -1);

	data = (xmms_gme_data_t *)xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, -1);

	if (gme_track_ended (data->emu))
		return 0;

	play_error = gme_play (data->emu, len/2, (short int *)buf);
	if (play_error) {
		XMMS_DBG ("gme_play returned an error: %s", play_error);
		xmms_error_set (err, XMMS_ERROR_GENERIC, play_error);
		return -1;
	}

	return len;
}

static gint64
xmms_gme_seek (xmms_xform_t *xform, gint64 samples,
               xmms_xform_seek_mode_t whence, xmms_error_t *err)
{
	xmms_gme_data_t *data;
	gint64 target_time;
	gint duration;
	int samplerate;

	g_return_val_if_fail (whence == XMMS_XFORM_SEEK_SET, -1);
	g_return_val_if_fail (xform, -1);

	data = (xmms_gme_data_t *) xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, -1);

	samplerate = data->samplerate;

	if (samples < 0) {
		xmms_error_set (err, XMMS_ERROR_INVAL,
		                "Trying to seek before start of stream");
		return -1;
	}

	target_time = (samples / samplerate) * 1000;
	xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, &duration);

	if (target_time > duration) {
		xmms_error_set (err, XMMS_ERROR_INVAL,
		                "Trying to seek past end of stream");
		return -1;
	}

	gme_seek (data->emu, target_time);

	return (gme_tell (data->emu) / 1000) * samplerate;
}

}
<|endoftext|>


<commit_before><commit_msg>Make the gl cubemap array init that takes a pointer list of cubemaps actually have parity to the updateTexture gl calls(aka, actually works).<commit_after><|endoftext|>


<commit_before>#include <Arduino.h>

#include <SPI.h>
#include <math.h>
#include "Heater.h"

// E0 Main extruder
const int E0_enable = 26; // low == enabled
const int E0_step = 34;
const int E0_dir = 43;
const int E0_MS1 = 65;
const int E0_MS2 = 66;
const int E0_digipot_channel = 0;
const float E0_steps_per_mm = 38.197;
const int E0_heater_pin = 9;
const int E0_digipot_setting = 100;
const bool E0_EXTRUDE = 0;
const bool E0_RETRACT = 1;
const int E0_thermistor = 0;
const int BETA_NOZZLE = 4267; // Semitec 104GT-2 Thermistor
const long R_ZERO = 100000; // Resistance at 25C
const int E0_SAMPLE_TIME = 500; // milliseconds
const int LED_PIN = 13;
const int MAX_VELOCITY = 10430; // 0.3183 increments/cycle * 2^15 = 10430
const int MAX_ACCELERATION = 4; // 1.2207*10^-4 * 2^15 = 4
int E0_acceleration = 0;
int E0_velocity = 0;
signed int E0_position = 0;
int target_velocity = 0;
unsigned long motor_test_time = 0;
int micro_step_scale = 1; // The micro step scale can be 1, 2, 4, or 16 based on
                          // the stepper driver data sheet

const float EXTRDUER_CONVERSION = 2.086;  // The desired speed in mm/min * EXTRDUER_CONVERSION
                                          // puts us into increment math

// Nozzle Heater
Heater E0_heater(E0_heater_pin, E0_thermistor, BETA_NOZZLE, R_ZERO, E0_SAMPLE_TIME, "E0");

// Digipot
const int slave_select_pin = 38;

// Fans
const int small_fan = 5;
const int large_fan = 8;
unsigned long last_fan_time = 0;
const int FAN_SAMPLE_TIME = 2000;

// Bed Heater
const int bed_heater_pin = 3;
const int BETA_BED = 3950;    // Not sure this is correct
const int bed_thermistor = 56;
const int bed_sample_time = 1000; // milliseconds
Heater bed_heater(bed_heater_pin, bed_thermistor, BETA_BED, R_ZERO, bed_sample_time, "Bed");

// Stepper Motor
const int MIN_HIGH_PULSE = 200; // microseconds
const int MIN_LOW_PULSE = 5; //microseconds

// betweenLayerRetract
long num_interrupts = 0;
bool bet_layer_retract_done = true;
bool prev_bet_layer_retract = true;
bool  S_retract = 0,
      S_between_layer = 0,
      S_extrude = 0,
      S_wait = 1,
      S_printing = 0;
int direction = 0;

// Inputs from robot
const int MAN_EXTRUDE = 84,
          HEAT_BED = 83,
          HEAT_NOZZLE = 82,
          PROG_FEED = 81,
          BETWEEN_LAYER_RETRACT = 80,
          ALL_STOP = 79;

// Outputs to robot
const int BED_AT_TEMP = 71,
          NOZZLE_AT_TEMP = 72;

// Report
unsigned long last_report_time = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(E0_enable, OUTPUT);
  pinMode(E0_step, OUTPUT);
  pinMode(E0_dir, OUTPUT);
  pinMode(E0_MS1, OUTPUT);
  pinMode(E0_MS2, OUTPUT);
  pinMode(slave_select_pin, OUTPUT);
  pinMode(small_fan, OUTPUT);
  pinMode(large_fan, OUTPUT);

  // Inputs from robot
  pinMode(MAN_EXTRUDE, INPUT_PULLUP);
  pinMode(HEAT_BED, INPUT_PULLUP);
  pinMode(HEAT_NOZZLE, INPUT_PULLUP);
  pinMode(PROG_FEED, INPUT_PULLUP);
  pinMode(BETWEEN_LAYER_RETRACT, INPUT_PULLUP);
  pinMode(ALL_STOP, INPUT_PULLUP);

  // Outputs to robot
  pinMode(BED_AT_TEMP, OUTPUT);
  pinMode(NOZZLE_AT_TEMP, OUTPUT);

  pinMode(LED_PIN, OUTPUT);

  Serial.begin(9600);

  /*
  The Rambo board has programmable potentiometers or 'digipots' for tuning
  each individual stepper motor. the following code handles that
  */
  SPI.begin();
  digitalWrite(slave_select_pin, LOW);
  SPI.transfer(E0_digipot_channel);
  SPI.transfer(E0_digipot_setting);
  SPI.end();
  digitalWrite(slave_select_pin, HIGH);

  digitalWrite(E0_MS1, LOW);
  digitalWrite(E0_MS2, LOW);
  digitalWrite(E0_dir, LOW);

  E0_heater.setTunings(50, 1, 9); // Initial Nozzle PID parameters
  E0_heater.setTargetTemp(100);
  bed_heater.setTunings(50, 0.5, 9); // Initial Bed PID Values
  bed_heater.setTargetTemp(35);

  // initialize timer 3 for the stepper motor interrupts
  noInterrupts();
  // clear current bit selections
  TCCR3A = 0;
  TCCR3B = 0;
  TCNT3 = 0;

  OCR3A = 1600;     // compare match register 10kHz
  TCCR3B |= (1 << WGM12); // CTC mode
  TCCR3B |= (1 << CS10); // No prescaling
  TIMSK3 |= (1 << OCIE3A); // enable timer compare interrupt
  interrupts(); // enable global interupts
}

/**
scaleMicroStep() checks the current commanded velocity and determines if it
is within one of the available micro step ranges. Using micro steps enables
better lower speed performance and more reliable accelerations from zero.
The available micro steps are 1 (full speed) 2, 4, and 16.
*/
void scaleMicroStep(){
  int holdScale = MAX_VELOCITY/abs(E0_velocity);
  if(holdScale >= 16){
    micro_step_scale = 16;
    digitalWrite(E0_MS1, HIGH);
    digitalWrite(E0_MS2, HIGH);
  }
  else if (holdScale >= 4){
    micro_step_scale = 4;
    digitalWrite(E0_MS1, LOW);
    digitalWrite(E0_MS2, HIGH);
  }
  else if (holdScale >= 2){
    micro_step_scale = 2;
    digitalWrite(E0_MS1, HIGH);
    digitalWrite(E0_MS2, LOW);
  }
  else{
    micro_step_scale = 1;
    digitalWrite(E0_MS1, LOW);
    digitalWrite(E0_MS2, LOW);
  }
  delayMicroseconds(2);
}

ISR(TIMER3_COMPA_vect){
  noInterrupts();

  E0_velocity = target_velocity == 0 ? 0 : E0_acceleration + E0_velocity;
  if(E0_velocity > MAX_VELOCITY){
    E0_velocity = MAX_VELOCITY;
  }
  else if(E0_velocity < -MAX_VELOCITY){
    E0_velocity = -MAX_VELOCITY;
  }
  if(E0_velocity < 0){ // Retract filament
    digitalWrite(E0_dir, HIGH);
  }
  else{ // Extrude filament
    digitalWrite(E0_dir, LOW);
  }

  scaleMicroStep();

  E0_position += E0_velocity*micro_step_scale;

  if(SREG & 0b00001000){ // The third bit in SREG is the overflow flag. If we overflow
                    // Then we know we should increment the stepper

    E0_position -= 0x8000; // Subtract a 1 in 16bit math
    digitalWrite(E0_step, HIGH);
    delayMicroseconds(2);
    digitalWrite(E0_step, LOW);
  }
  if(target_velocity - E0_velocity > MAX_ACCELERATION){
    E0_acceleration = MAX_ACCELERATION;
  }
  else if(E0_velocity - target_velocity > MAX_ACCELERATION){
    E0_acceleration = -MAX_ACCELERATION;
  }
  else{
    E0_acceleration = 0;
  }
  num_interrupts += 1;
  interrupts();
}

void checkStates(){
  bool end_Layer = !digitalRead(BETWEEN_LAYER_RETRACT);
  int retract_dist = 1810;
  S_printing = (S_printing | (S_wait & digitalRead(PROG_FEED))) & !S_retract;
  S_wait = (S_wait | (S_extrude & (num_interrupts > retract_dist))) & !S_printing;
  S_extrude = (S_extrude | (S_between_layer & !end_Layer)) & !S_wait;
  S_between_layer = (S_between_layer | (S_retract & (num_interrupts > retract_dist))) & !S_extrude;
  S_retract = (S_retract | (S_printing & end_Layer)) & !S_between_layer;

  if((S_wait & !S_printing) | (S_between_layer & !S_extrude)){
    num_interrupts = 0;
    target_velocity = 0;
    E0_acceleration = 0;
  }
  else if(S_printing & !S_retract){
    num_interrupts = 0;
    if
  }
  else if(S_retract & !S_between_layer){
    E0_acceleration = -MAX_ACCELERATION;
    target_velocity = -MAX_VELOCITY;
  }
  else if(S_extrude & !S_wait){
    E0_acceleration = MAX_ACCELERATION;
    target_velocity = MAX_VELOCITY;
  }
}

void setFans(){
  /*
    Tests the current temperature of the nozzle and then turns on the
    fans if they are above their temperatures.
  */
  unsigned long now = millis();
  if(now - last_fan_time > FAN_SAMPLE_TIME){
    float currTemp = E0_heater.getCurrTemp();
    if (currTemp > 100) {
      analogWrite(small_fan, 255);
    }
    if(currTemp > 180){
      analogWrite(large_fan, 255);
    }
    last_fan_time = now;
  }
}

void testMotor(){
  noInterrupts();
  unsigned long ellapsed = millis() - motor_test_time;
  if((E0_velocity >= MAX_VELOCITY || E0_velocity <= -MAX_VELOCITY) && motor_test_time==0){
    motor_test_time = millis();
    // E0_acceleration *= -1;
  }
  else if(motor_test_time >0 && ellapsed < 1500){

  }
  else if(motor_test_time>0 && ellapsed >= 1500){
    motor_test_time = 0;
    E0_acceleration *= -1;
  }
  interrupts();
}

void report(){
  unsigned long now = millis();
  if(now - last_report_time > 1000){
    Serial.print("velocity target: ");
    Serial.println(target_velocity);
    Serial.print("Accel: ");
    Serial.println(E0_acceleration);
    Serial.print("MAN_EXTRUDE: ");
    Serial.println(digitalRead(MAN_EXTRUDE));
    Serial.println();

    last_report_time = now;
  }
}

void loop() {
  if(!digitalRead(HEAT_NOZZLE)){
    E0_heater.setTargetTemp(100);
    if(E0_heater.atTemp()){
      digitalWrite(NOZZLE_AT_TEMP, HIGH);
    }
    else{
      digitalWrite(NOZZLE_AT_TEMP, LOW);
    }
  }
  else{
    E0_heater.setTargetTemp(0);
  }
  if(!digitalRead(MAN_EXTRUDE)){
    target_velocity = 100*EXTRDUER_CONVERSION;
  }
  else{
    target_velocity = 0;
  }
  E0_heater.compute();
  bed_heater.compute();
  checkStates();
  setFans();
  report();
}
<commit_msg>Impliment states<commit_after>#include <Arduino.h>

#include <SPI.h>
#include <math.h>
#include "Heater.h"

// E0 Main extruder
const int E0_enable = 26; // low == enabled
const int E0_step = 34;
const int E0_dir = 43;
const int E0_MS1 = 65;
const int E0_MS2 = 66;
const int E0_digipot_channel = 0;
const float E0_steps_per_mm = 38.197;
const int E0_heater_pin = 9;
const int E0_digipot_setting = 100;
const bool E0_EXTRUDE = 0;
const bool E0_RETRACT = 1;
const int E0_thermistor = 0;
const int BETA_NOZZLE = 4267; // Semitec 104GT-2 Thermistor
const long R_ZERO = 100000; // Resistance at 25C
const int E0_SAMPLE_TIME = 500; // milliseconds
const int LED_PIN = 13;
const int MAX_VELOCITY = 10430; // 0.3183 increments/cycle * 2^15 = 10430
const int MAX_ACCELERATION = 4; // 1.2207*10^-4 * 2^15 = 4
const float VELOCITY_CONVERSION = 2.086;  // The desired speed in mm/min * EXTRDUER_CONVERSION
                                          // puts us into increment math
const int PROGRAM_FEED_RATE = 30 * VELOCITY_CONVERSION;
int E0_acceleration = 0;
int E0_velocity = 0;
signed int E0_position = 0;
int target_velocity = 0;
unsigned long motor_test_time = 0;
int micro_step_scale = 1; // The micro step scale can be 1, 2, 4, or 16 based on
                          // the stepper driver data sheet

// Nozzle Heater
Heater E0_heater(E0_heater_pin, E0_thermistor, BETA_NOZZLE, R_ZERO, E0_SAMPLE_TIME, "E0");

// Digipot
const int slave_select_pin = 38;

// Fans
const int small_fan = 5;
const int large_fan = 8;
unsigned long last_fan_time = 0;
const int FAN_SAMPLE_TIME = 2000;

// Bed Heater
const int bed_heater_pin = 3;
const int BETA_BED = 3950;    // Not sure this is correct
const int bed_thermistor = 56;
const int bed_sample_time = 1000; // milliseconds
Heater bed_heater(bed_heater_pin, bed_thermistor, BETA_BED, R_ZERO, bed_sample_time, "Bed");

// Stepper Motor
const int MIN_HIGH_PULSE = 200; // microseconds
const int MIN_LOW_PULSE = 5; //microseconds

// betweenLayerRetract
const int retract_dist = 1810; // TODO: create constant for converting mm to dist
long num_interrupts = 0;
bool bet_layer_retract_done = true;
bool prev_bet_layer_retract = true;
bool  S_retract = 0,
      S_between_layer = 0,
      S_extrude = 0,
      S_wait = 0,
      S_printing = 0,
      S_manual_extrude = 0,
      S_ALL_STOP = 0,
      S0 = 1,
      D1 = 0,
      D2 = 0,
      D3 = 0;
int direction = 0;

String currState = "";

// Inputs from robot
const int MAN_EXTRUDE = 84,
          HEAT_BED = 83,
          HEAT_NOZZLE = 82,
          PROG_FEED = 81,
          BETWEEN_LAYER_RETRACT = 80,
          ALL_STOP = 79;

bool man_extrude,
    heat_bed,
    heat_nozzle,
    prog_feed,
    between_layer_retract,
    all_stop;

// Outputs to robot
const int BED_AT_TEMP = 71,
          NOZZLE_AT_TEMP = 72;

// Report
unsigned long last_report_time = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(E0_enable, OUTPUT);
  pinMode(E0_step, OUTPUT);
  pinMode(E0_dir, OUTPUT);
  pinMode(E0_MS1, OUTPUT);
  pinMode(E0_MS2, OUTPUT);
  pinMode(slave_select_pin, OUTPUT);
  pinMode(small_fan, OUTPUT);
  pinMode(large_fan, OUTPUT);

  // Inputs from robot
  pinMode(MAN_EXTRUDE, INPUT_PULLUP);
  pinMode(HEAT_BED, INPUT_PULLUP);
  pinMode(HEAT_NOZZLE, INPUT_PULLUP);
  pinMode(PROG_FEED, INPUT_PULLUP);
  pinMode(BETWEEN_LAYER_RETRACT, INPUT_PULLUP);
  pinMode(ALL_STOP, INPUT_PULLUP);

  // Outputs to robot
  pinMode(BED_AT_TEMP, OUTPUT);
  pinMode(NOZZLE_AT_TEMP, OUTPUT);

  pinMode(LED_PIN, OUTPUT);

  Serial.begin(9600);

  /*
  The Rambo board has programmable potentiometers or 'digipots' for tuning
  each individual stepper motor. the following code handles that
  */
  SPI.begin();
  digitalWrite(slave_select_pin, LOW);
  SPI.transfer(E0_digipot_channel);
  SPI.transfer(E0_digipot_setting);
  SPI.end();
  digitalWrite(slave_select_pin, HIGH);

  digitalWrite(E0_MS1, LOW);
  digitalWrite(E0_MS2, LOW);
  digitalWrite(E0_dir, LOW);

  E0_heater.setTunings(50, 1, 9); // Initial Nozzle PID parameters
  E0_heater.setTargetTemp(100);
  bed_heater.setTunings(50, 0.5, 9); // Initial Bed PID Values
  bed_heater.setTargetTemp(35);

  // initialize timer 3 for the stepper motor interrupts
  noInterrupts();
  // clear current bit selections
  TCCR3A = 0;
  TCCR3B = 0;
  TCNT3 = 0;

  OCR3A = 1600;     // compare match register 10kHz
  TCCR3B |= (1 << WGM12); // CTC mode
  TCCR3B |= (1 << CS10); // No prescaling
  TIMSK3 |= (1 << OCIE3A); // enable timer compare interrupt
  interrupts(); // enable global interupts
}

/**
scaleMicroStep() checks the current commanded velocity and determines if it
is within one of the available micro step ranges. Using micro steps enables
better lower speed performance and more reliable accelerations from zero.
The available micro steps are 1 (full speed) 2, 4, and 16.
*/
void scaleMicroStep(){
  int holdScale = MAX_VELOCITY/abs(E0_velocity);
  if(holdScale >= 16){
    micro_step_scale = 16;
    digitalWrite(E0_MS1, HIGH);
    digitalWrite(E0_MS2, HIGH);
  }
  else if (holdScale >= 4){
    micro_step_scale = 4;
    digitalWrite(E0_MS1, LOW);
    digitalWrite(E0_MS2, HIGH);
  }
  else if (holdScale >= 2){
    micro_step_scale = 2;
    digitalWrite(E0_MS1, HIGH);
    digitalWrite(E0_MS2, LOW);
  }
  else{
    micro_step_scale = 1;
    digitalWrite(E0_MS1, LOW);
    digitalWrite(E0_MS2, LOW);
  }
  delayMicroseconds(2);
}

ISR(TIMER3_COMPA_vect){
  noInterrupts();

  int velocity_error = target_velocity - E0_velocity;

  if(target_velocity == 0){ // If we are not supposed to be moving
    // Note: This code does not decelerate to 0 if target_velocity == 0
    E0_velocity = 0;
    E0_acceleration = 0;
  }
  else if(abs(velocity_error)/2 <= MAX_ACCELERATION){
    // If we are within 1/2 of an acceleration step of our target velocity then
    // stop accelerating/
    E0_acceleration = 0;
  }
  else if(velocity_error > 0){ // We need to speed up
    E0_acceleration = MAX_ACCELERATION;
  }
  else{ // We need to slow down
    E0_acceleration = -MAX_ACCELERATION;
  }

  E0_velocity += E0_acceleration;

  if(E0_velocity > MAX_VELOCITY){
    E0_velocity = MAX_VELOCITY;
  }
  else if(E0_velocity < -MAX_VELOCITY){
    E0_velocity = -MAX_VELOCITY;
  }
  if(E0_velocity < 0){ // Retract filament
    digitalWrite(E0_dir, HIGH);
  }
  else{ // Extrude filament
    digitalWrite(E0_dir, LOW);
  }

  scaleMicroStep();

  E0_position += E0_velocity*micro_step_scale;

  if(SREG & 0b00001000){ // The third bit in SREG is the overflow flag. If we overflow
                    // Then we know we should increment the stepper

    E0_position -= 0x8000; // Subtract a 1 in 16bit math
    digitalWrite(E0_step, HIGH);
    delayMicroseconds(2);
    digitalWrite(E0_step, LOW);
  }
  if(target_velocity - E0_velocity > MAX_ACCELERATION){
    E0_acceleration = MAX_ACCELERATION;
  }
  else if(E0_velocity - target_velocity > MAX_ACCELERATION){
    E0_acceleration = -MAX_ACCELERATION;
  }
  else{
    E0_acceleration = 0;
  }
  num_interrupts += 1;
  interrupts();
}

void checkStates(){
  man_extrude = !digitalRead(MAN_EXTRUDE);
  heat_bed = !digitalRead(HEAT_BED);
  heat_nozzle = !digitalRead(HEAT_NOZZLE);
  prog_feed = !digitalRead(PROG_FEED);
  between_layer_retract = !digitalRead(BETWEEN_LAYER_RETRACT);
  all_stop = !digitalRead(ALL_STOP);

  S0 = (S0 || D1 || D2 || D3) && !(S_manual_extrude || S_printing);
  S_manual_extrude = (S_manual_extrude || (S0 && man_extrude)) && !D1;
  D1 = (D1 || (S_manual_extrude && !man_extrude)) && !S0;
  S_printing = (S_printing || (S0 && prog_feed)) && !(D2 || S_retract);
  S_retract = (S_retract || (S_printing && between_layer_retract)) && !S_wait;
  S_wait = (S_wait || (num_interrupts >= retract_dist)) && !(S_extrude || D2);
  S_extrude = (S_extrude || (S_wait && !between_layer_retract)) && !S_printing;
  D2 = (D2 ||((S_wait || S_printing) && !prog_feed)) && !S0;
  D3 = (D3 || (S_ALL_STOP && !(prog_feed && heat_bed && heat_nozzle
                          && between_layer_retract && all_stop))) && !S0;
  S_ALL_STOP = (S_ALL_STOP || all_stop) & !D3;
  if(S_ALL_STOP){
    S0  = S_manual_extrude = D1 = S_printing = S_retract = S_wait = S_extrude
        = D2 = D3 = 0;
    E0_heater.setTargetTemp(0);
    bed_heater.setTargetTemp(0);
    target_velocity = 0;
    currState = "ALL_STOP";
  }
  else if(S0 && !(S_manual_extrude || S_printing)){
    target_velocity = 0;
    currState = "S0";
  }
  else if(S_manual_extrude && !D1){
    target_velocity = 100 * VELOCITY_CONVERSION; // Manual extrude speed
    currState = "Manul Extrude";
  }
  else if(S_printing && !(D2 || S_retract)){
    num_interrupts = 0;
    target_velocity = PROGRAM_FEED_RATE;
    currState = "Printing";
  }
  else if(S_retract && !S_wait){
    target_velocity = -MAX_VELOCITY;
    currState = "Retract";
  }
  else if(S_wait && !(S_extrude || D2)){
    num_interrupts = 0;
    target_velocity = 0;
    currState = "Wait";
  }
  else if(S_extrude && !S_printing){
    target_velocity = MAX_VELOCITY;
    currState = "Extrude";
  }
}

void setFans(){
  /*
    Tests the current temperature of the nozzle and then turns on the
    fans if they are above their temperatures.
  */
  unsigned long now = millis();
  if(now - last_fan_time > FAN_SAMPLE_TIME){
    float currTemp = E0_heater.getCurrTemp();
    if (currTemp > 100) {
      analogWrite(small_fan, 255);
    }
    if(currTemp > 180){
      analogWrite(large_fan, 255);
    }
    last_fan_time = now;
  }
}

void testMotor(){
  noInterrupts();
  unsigned long ellapsed = millis() - motor_test_time;
  if((E0_velocity >= MAX_VELOCITY || E0_velocity <= -MAX_VELOCITY) && motor_test_time==0){
    motor_test_time = millis();
    // E0_acceleration *= -1;
  }
  else if(motor_test_time >0 && ellapsed < 1500){

  }
  else if(motor_test_time>0 && ellapsed >= 1500){
    motor_test_time = 0;
    E0_acceleration *= -1;
  }
  interrupts();
}

void report(){
  unsigned long now = millis();
  if(now - last_report_time > 1000){
    Serial.print("velocity target: ");
    Serial.println(target_velocity);
    Serial.print("Accel: ");
    Serial.print("Curr State: ");
    Serial.println();

    last_report_time = now;
  }
}

void loop() {
  if(!digitalRead(HEAT_NOZZLE)){
    E0_heater.setTargetTemp(100);
    if(E0_heater.atTemp()){
      digitalWrite(NOZZLE_AT_TEMP, HIGH);
    }
    else{
      digitalWrite(NOZZLE_AT_TEMP, LOW);
    }
  }
  else{
    E0_heater.setTargetTemp(0);
  }
  if(!digitalRead(MAN_EXTRUDE)){
    target_velocity = 100*VELOCITY_CONVERSION;
  }
  else{
    target_velocity = 0;
  }
  E0_heater.compute();
  bed_heater.compute();
  checkStates();
  setFans();
  report();
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2008-2014 The Communi Project
*
* 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.
*/

#include "zncplugin.h"
#include "zncmanager.h"
#include "textdocument.h"
#include <IrcConnection>
#include <IrcBufferModel>
#include <IrcBuffer>

ZncPlugin::ZncPlugin(QObject* parent) : QObject(parent)
{
}

void ZncPlugin::connectionAdded(IrcConnection* connection)
{
    ZncManager* manager = new ZncManager(connection);
    manager->setModel(connection->findChild<IrcBufferModel*>());
    connect(manager, SIGNAL(playbackBegin(IrcBuffer*)), this, SLOT(onPlaybackBegin(IrcBuffer*)));
    connect(manager, SIGNAL(playbackEnd(IrcBuffer*)), this, SLOT(onPlaybackEnd(IrcBuffer*)));
}

void ZncPlugin::documentAdded(TextDocument* document)
{
    d.documents.insert(document->buffer(), document);
}

void ZncPlugin::documentRemoved(TextDocument* document)
{
    d.documents.remove(document->buffer(), document);
}

void ZncPlugin::onPlaybackBegin(IrcBuffer* buffer)
{
    foreach (TextDocument* doc, d.documents.values(buffer))
        doc->beginLowlight();
}

void ZncPlugin::onPlaybackEnd(IrcBuffer* buffer)
{
    foreach (TextDocument* doc, d.documents.values(buffer))
        doc->endLowlight();
}
<commit_msg>Disable broken playback highlight for now<commit_after>/*
* Copyright (C) 2008-2014 The Communi Project
*
* 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.
*/

#include "zncplugin.h"
#include "zncmanager.h"
#include "textdocument.h"
#include <IrcConnection>
#include <IrcBufferModel>
#include <IrcBuffer>

ZncPlugin::ZncPlugin(QObject* parent) : QObject(parent)
{
}

void ZncPlugin::connectionAdded(IrcConnection* connection)
{
    ZncManager* manager = new ZncManager(connection);
    manager->setModel(connection->findChild<IrcBufferModel*>());
// TODO:
//    connect(manager, SIGNAL(playbackBegin(IrcBuffer*)), this, SLOT(onPlaybackBegin(IrcBuffer*)));
//    connect(manager, SIGNAL(playbackEnd(IrcBuffer*)), this, SLOT(onPlaybackEnd(IrcBuffer*)));
}

void ZncPlugin::documentAdded(TextDocument* document)
{
    d.documents.insert(document->buffer(), document);
}

void ZncPlugin::documentRemoved(TextDocument* document)
{
    d.documents.remove(document->buffer(), document);
}

void ZncPlugin::onPlaybackBegin(IrcBuffer* buffer)
{
    foreach (TextDocument* doc, d.documents.values(buffer))
        doc->beginLowlight();
}

void ZncPlugin::onPlaybackEnd(IrcBuffer* buffer)
{
    foreach (TextDocument* doc, d.documents.values(buffer))
        doc->endLowlight();
}
<|endoftext|>


<commit_before><commit_msg>add a missing character.<commit_after><|endoftext|>


<commit_before><commit_msg>Simple Driver: Changed Perturbation<commit_after><|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2015-2016.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef WORD_SPOTTER_HMM_HPP
#define WORD_SPOTTER_HMM_HPP

#ifndef SPOTTER_NO_HMM

#include <mlpack/core.hpp>
#include <mlpack/methods/hmm/hmm.hpp>
#include <mlpack/methods/gmm/gmm.hpp>

using GMM = mlpack::gmm::GMM;

template<typename Distribution>
using HMM = mlpack::hmm::HMM<Distribution>;

using gmm_p = std::unique_ptr<GMM>;
using hmm_p = std::unique_ptr<HMM<GMM>>;

//Number of gaussians for the HMM
static constexpr const std::size_t n_hmm_gaussians = 1;

//Number of gaussians for the GMM
static constexpr const std::size_t n_gmm_gaussians = 16;

//Number of states per character
static constexpr const auto n_states_per_char = 1;

template <typename RefFunctor>
gmm_p train_global_hmm(names train_word_names, RefFunctor functor) {
    dll::auto_timer timer("gmm_train");

    auto ref_a = functor(train_word_names);

    const auto n_features = ref_a[0][0].size();

    auto gmm = std::make_unique<GMM>(n_gmm_gaussians, n_features);

    //TODO Better Configure how the subset if sleected
    std::size_t step = 5;

    //Collect information on the dataset

    std::size_t n_observations = 0;
    std::size_t n_images = 0;

    for(std::size_t image = 0; image < ref_a.size(); image += step){
        n_observations += ref_a[image].size();
        ++n_images;
    }

    //Flatten all the images

    arma::mat flatten_mat(n_features, n_observations);
    std::size_t o = 0;

    for(std::size_t image = 0; image < ref_a.size(); image += step){
        auto& ref_image = ref_a[image];

        auto width = ref_image.size();

        for(std::size_t i = 0; i < width; ++i){
            auto od = o++;
            for(std::size_t j = 0; j < n_features; ++j){
                flatten_mat(j, od) = ref_image[i][j];
            }
        }
    }

    try {
        std::cout << "Start training the GMM" << std::endl;
        std::cout << "\tn_images: " << n_images << std::endl;
        std::cout << "\tn_observations=" << n_observations << std::endl;
        std::cout << "\tn_total_features=" << n_observations * 9 << std::endl;

        gmm->Train(flatten_mat);

        std::cout << "GMM succesfully converged (with " << n_images << " images)" << std::endl;
    } catch (const std::logic_error& e){
        std::cout << "frakking GMM failed: " << e.what() << std::endl;
    } catch (const std::runtime_error& e){
        std::cout << "frakking GMM failed to converge: " << e.what() << std::endl;
    }

    return gmm;
}

template <typename Dataset, typename Ref>
hmm_p train_ref_hmm(const Dataset& dataset, Ref& ref_a, names training_images) {
    dll::auto_timer timer("hmm_train");

    auto characters = dataset.word_labels.at(training_images[0]).size();

    const auto n_states = characters * n_states_per_char;
    const auto n_features = ref_a[0][0].size();

    auto hmm = std::make_unique<HMM<GMM>>(n_states, GMM(n_hmm_gaussians, n_features));

    std::vector<arma::mat> images(ref_a.size());
    std::vector<arma::Row<size_t>> labels(ref_a.size());

    for(std::size_t image = 0; image < ref_a.size(); ++image){
        auto& ref_image = ref_a[image];

        auto width = ref_image.size();

        images[image] = arma::mat(n_features, width);
        labels[image] = arma::Row<size_t>(width);

        std::size_t current_label = 0;
        std::size_t label_distance = width / n_states;

        for(std::size_t i = 0; i < width; ++i){
            for(std::size_t j = 0; j < ref_image[i].size(); ++j){
                images[image](j, i) = ref_image[i][j];
            }

            labels[image](i) = std::min(current_label, n_states - 1);

            if(i > 0 && i % label_distance == 0){
                ++current_label;
            }
        }
    }

    try {
        hmm->Train(images, labels);

        std::cout << "HMM succesfully converged (with " << images.size() << " images)" << std::endl;
    } catch (const std::logic_error& e){
        std::cout << "frakking HMM failed: " << e.what() << std::endl;
        std::cout << "\tn_images: " << images.size() << std::endl;
        std::cout << "\tn_features: " << n_features << std::endl;
        std::cout << "\tn_states: " << n_states << std::endl;

        for(std::size_t i = 0; i < images.size(); ++i){
            auto& image = images[i];
            auto& label = labels[i];

            image.print("Image");
            label.print("Label");
        }
    } catch (const std::runtime_error& e){
        std::cout << "frakking HMM failed to converge: " << e.what() << std::endl;
        std::cout << "\tn_images: " << images.size() << std::endl;
        std::cout << "\tn_features: " << n_features << std::endl;
        std::cout << "\tn_states: " << n_states << std::endl;
    }

    return hmm;
}

template <typename Dataset, typename V1>
double hmm_distance(const Dataset& dataset, const gmm_p& gmm, const hmm_p& hmm, std::size_t pixel_width, const V1& test_image, names training_images) {
    double ref_width = 0;

    for(auto& image : training_images){
        ref_width += dataset.word_images.at(image + ".png").size().width;
    }

    ref_width /= training_images.size();

    auto ratio = ref_width / pixel_width;

    if (ratio > 2.0 || ratio < 0.5) {
        return 1e8;
    }

    const auto n_features = test_image[0].size();
    const auto width = test_image.size();

    arma::mat image(n_features, width);

    for(std::size_t i = 0; i < width; ++i){
        for(std::size_t j = 0; j < test_image[i].size(); ++j){
            image(j, i) = test_image[i][j];
        }
    }

    auto gmm_likelihood = [&gmm](auto& image){
        auto likelihood = 0.0;

        for(std::size_t i = 0; i < image.n_cols; ++i){
            double p = gmm->Probability(image.col(i));

            if(!std::isfinite(p)){
                std::cerr << "WARNING: p(x|GMM) not finite: " << p << std::endl;
            }

            double logp;

            if(p == 0.0){
                std::cerr << "WARNING: p(x|GMM) == 0 col: " << i << std::endl;
                logp = -100;
            } else {
                logp = std::log(p);
            }

            if(!std::isfinite(logp)){
                std::cerr << "WARNING: log(p(x|GMM)) not finite: " << logp << std::endl;
            }

            likelihood += logp;
        }

        return likelihood;
    };

    auto p_hmm = hmm->LogLikelihood(image);
    auto p_gmm = gmm_likelihood(image);

    if(!std::isfinite(p_hmm)){
        std::cerr << "WARNING: p(X|HMM) not finite: " << p_hmm << std::endl;
        return 1e8; //TODO WHY
    }

    if(!std::isfinite(p_gmm)){
        std::cerr << "WARNING: p(X|GMM) not finite: " << p_gmm << std::endl;
    }

    return -(p_hmm / p_gmm);
}

#else

using gmm_p = int;
using hmm_p = int;

template <typename RefFunctor>
gmm_p train_global_hmm(names /*train_word_names*/, RefFunctor /*functor*/) {
    //Disabled HMM
    std::cerr << "HMM has been disabled, -hmm should not be used" << std::endl;
}

template <typename Dataset, typename Ref>
hmm_p train_ref_hmm(const Dataset& /*dataset*/, Ref& /*ref_a*/, names /*training_images*/) {
    //Disabled HMM
    std::cerr << "HMM has been disabled, -hmm should not be used" << std::endl;
}

template <typename Dataset, typename V1>
double hmm_distance(const Dataset& /*dataset*/, const gmm_p& /*global_hmm*/, const hmm_p& /*hmm*/, std::size_t /*pixel_width*/, const V1& /*test_image*/, names /*training_images*/) {
    //Disabled HMM
    std::cerr << "HMM has been disabled, -hmm should not be used" << std::endl;
}

#endif

#endif
<commit_msg>Tests<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2015-2016.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef WORD_SPOTTER_HMM_HPP
#define WORD_SPOTTER_HMM_HPP

#ifndef SPOTTER_NO_HMM

#include <random>

#include <mlpack/core.hpp>
#include <mlpack/methods/hmm/hmm.hpp>
#include <mlpack/methods/gmm/gmm.hpp>

using GMM = mlpack::gmm::GMM;

template<typename Distribution>
using HMM = mlpack::hmm::HMM<Distribution>;

using gmm_p = std::unique_ptr<GMM>;
using hmm_p = std::unique_ptr<HMM<GMM>>;

//Number of gaussians for the HMM
static constexpr const std::size_t n_hmm_gaussians = 1;

//Number of gaussians for the GMM
static constexpr const std::size_t n_gmm_gaussians = 16;

//Number of states per character
static constexpr const auto n_states_per_char = 2;

template <typename RefFunctor>
gmm_p train_global_hmm(names train_word_names, RefFunctor functor) {
    dll::auto_timer timer("gmm_train");

    auto ref_a = functor(train_word_names);

    const auto n_features = ref_a[0][0].size();

    auto gmm = std::make_unique<GMM>(n_gmm_gaussians, n_features);

    //TODO Better Configure how the subset if selected
    std::size_t step = 5;

    //Collect information on the dataset

    std::size_t n_observations = 0;
    std::size_t n_images = 0;

    for(std::size_t image = 0; image < ref_a.size(); image += step){
        n_observations += ref_a[image].size();
        ++n_images;
    }

    //Flatten all the images

    arma::mat flatten_mat(n_features, n_observations);
    std::size_t o = 0;

    for(std::size_t image = 0; image < ref_a.size(); image += step){
        auto& ref_image = ref_a[image];

        auto width = ref_image.size();

        for(std::size_t i = 0; i < width; ++i){
            auto od = o++;
            for(std::size_t j = 0; j < n_features; ++j){
                flatten_mat(j, od) = ref_image[i][j];
            }
        }
    }

    try {
        std::cout << "Start training the GMM" << std::endl;
        std::cout << "\tn_images: " << n_images << std::endl;
        std::cout << "\tn_observations=" << n_observations << std::endl;
        std::cout << "\tn_total_features=" << n_observations * 9 << std::endl;

        gmm->Train(flatten_mat);

        std::cout << "GMM succesfully converged (with " << n_images << " images)" << std::endl;
    } catch (const std::logic_error& e){
        std::cout << "frakking GMM failed: " << e.what() << std::endl;
    } catch (const std::runtime_error& e){
        std::cout << "frakking GMM failed to converge: " << e.what() << std::endl;
    }

    return gmm;
}

template <typename Dataset, typename Ref>
hmm_p train_ref_hmm(const Dataset& dataset, Ref& ref_a, names training_images) {
    dll::auto_timer timer("hmm_train");

    auto characters = dataset.word_labels.at(training_images[0]).size();

    const auto n_states = characters * n_states_per_char;
    const auto n_features = ref_a[0][0].size();

    auto hmm = std::make_unique<HMM<GMM>>(n_states, GMM(n_hmm_gaussians, n_features));

    //Collect the standard deviations

    std::vector<double> deviations(n_features);

    for(std::size_t f = 0; f < n_features; ++f){
        double mean = 0.0;
        std::size_t n = 0;

        for(auto& image : ref_a){
            for(auto& column : image){
                mean += column[f];
            }
            n += image.size();
        }

        mean /= n;

        double stddev = 0.0;

        for(auto& image : ref_a){
            for(auto& column : image){
                stddev += (column[f] - mean) * (column[f] - mean);
            }
        }

        deviations[f] = std::sqrt(stddev / n);
    }

    static std::default_random_engine rand_engine(std::time(nullptr));

    // Copy the input (for salting)
    auto reference = ref_a;
    reference.clear();

    static constexpr const std::size_t salts = 5;
    static constexpr const double salt = 0.05;

    for(auto& image : ref_a){
        for (std::size_t s = 0; s < salts; ++s) {
            auto copy = image;

            if(salt > 0.0){
                for (auto& column : copy) {
                    for (std::size_t f = 0; f < n_features; ++f) {
                        std::normal_distribution<double> dist(0.0, salt * deviations[f]);
                        column[f] += dist(rand_engine);
                    }
                }
            }

            reference.push_back(copy);
        }
    }

    std::vector<arma::mat> images(reference.size());
    std::vector<arma::Row<size_t>> labels(reference.size());

    for(std::size_t image = 0; image < reference.size(); ++image){
        auto& ref_image = reference[image];

        auto width = ref_image.size();

        images[image] = arma::mat(n_features, width);
        labels[image] = arma::Row<size_t>(width);

        std::size_t current_label = 0;
        std::size_t label_distance = width / n_states;

        for(std::size_t i = 0; i < width; ++i){
            for(std::size_t j = 0; j < ref_image[i].size(); ++j){
                images[image](j, i) = ref_image[i][j];
            }

            labels[image](i) = std::min(current_label, n_states - 1);

            if(i > 0 && i % label_distance == 0){
                ++current_label;
            }
        }
    }

    try {
        hmm->Train(images, labels);

        std::cout << "HMM succesfully converged (with " << images.size() << " images)" << std::endl;
    } catch (const std::logic_error& e){
        std::cout << "frakking HMM failed: " << e.what() << std::endl;
        std::cout << "\tn_images: " << images.size() << std::endl;
        std::cout << "\tn_features: " << n_features << std::endl;
        std::cout << "\tn_states: " << n_states << std::endl;

        for(std::size_t i = 0; i < images.size(); ++i){
            auto& image = images[i];
            auto& label = labels[i];

            image.print("Image");
            label.print("Label");
        }
    } catch (const std::runtime_error& e){
        std::cout << "frakking HMM failed to converge: " << e.what() << std::endl;
        std::cout << "\tn_images: " << images.size() << std::endl;
        std::cout << "\tn_features: " << n_features << std::endl;
        std::cout << "\tn_states: " << n_states << std::endl;
    }

    return hmm;
}

template <typename Dataset, typename V1>
double hmm_distance(const Dataset& dataset, const gmm_p& gmm, const hmm_p& hmm, std::size_t pixel_width, const V1& test_image, names training_images) {
    double ref_width = 0;

    for(auto& image : training_images){
        ref_width += dataset.word_images.at(image + ".png").size().width;
    }

    ref_width /= training_images.size();

    auto ratio = ref_width / pixel_width;

    if (ratio > 2.0 || ratio < 0.5) {
        return 1e8;
    }

    const auto n_features = test_image[0].size();
    const auto width = test_image.size();

    arma::mat image(n_features, width);

    for(std::size_t i = 0; i < width; ++i){
        for(std::size_t j = 0; j < test_image[i].size(); ++j){
            image(j, i) = test_image[i][j];
        }
    }

    auto gmm_likelihood = [&gmm](auto& image){
        auto likelihood = 0.0;

        for(std::size_t i = 0; i < image.n_cols; ++i){
            double p = gmm->Probability(image.col(i));

            if(!std::isfinite(p)){
                std::cerr << "WARNING: p(x|GMM) not finite: " << p << std::endl;
            }

            double logp;

            if(p == 0.0){
                std::cerr << "WARNING: p(x|GMM) == 0 col: " << i << std::endl;
                logp = -100;
            } else {
                logp = std::log(p);
            }

            if(!std::isfinite(logp)){
                std::cerr << "WARNING: log(p(x|GMM)) not finite: " << logp << std::endl;
            }

            likelihood += logp;
        }

        return likelihood;
    };

    auto p_hmm = hmm->LogLikelihood(image);
    auto p_gmm = gmm_likelihood(image);

    if(!std::isfinite(p_hmm)){
        std::cerr << "WARNING: p(X|HMM) not finite: " << p_hmm << std::endl;
        return 1e8; //TODO WHY
    }

    if(!std::isfinite(p_gmm)){
        std::cerr << "WARNING: p(X|GMM) not finite: " << p_gmm << std::endl;
    }

    return -(p_hmm / p_gmm);
}

#else

using gmm_p = int;
using hmm_p = int;

template <typename RefFunctor>
gmm_p train_global_hmm(names /*train_word_names*/, RefFunctor /*functor*/) {
    //Disabled HMM
    std::cerr << "HMM has been disabled, -hmm should not be used" << std::endl;
}

template <typename Dataset, typename Ref>
hmm_p train_ref_hmm(const Dataset& /*dataset*/, Ref& /*ref_a*/, names /*training_images*/) {
    //Disabled HMM
    std::cerr << "HMM has been disabled, -hmm should not be used" << std::endl;
}

template <typename Dataset, typename V1>
double hmm_distance(const Dataset& /*dataset*/, const gmm_p& /*global_hmm*/, const hmm_p& /*hmm*/, std::size_t /*pixel_width*/, const V1& /*test_image*/, names /*training_images*/) {
    //Disabled HMM
    std::cerr << "HMM has been disabled, -hmm should not be used" << std::endl;
}

#endif

#endif
<|endoftext|>