<commit_before>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

    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 or 3 of the License.

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

    You should have received a copy of the GNU Lesser General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <gst/interfaces/propertyprobe.h>
#include "devicemanager.h"
#include "backend.h"
#include "gsthelper.h"
#include "videowidget.h"
#include "glrenderer.h"
#include "widgetrenderer.h"
#include "x11renderer.h"
#include "artssink.h"
#include "pulsesupport.h"

#ifdef USE_ALSASINK2
#include "alsasink2.h"
#endif

/*
 * This class manages the list of currently
 * active output devices
 */

QT_BEGIN_NAMESPACE

namespace Phonon
{
namespace Gstreamer
{

AudioDevice::AudioDevice(DeviceManager *manager, const QByteArray &gstId)
        : gstId(gstId)
{
    // This should never be called when PulseAudio is active.
    Q_ASSERT(!PulseSupport::getInstance()->isActive());

    id = manager->allocateDeviceId();
    icon = "audio-card";

    //get name from device
    if (gstId == "default") {
        description = "Default audio device";
    } else {
        GstElement *aSink= manager->createAudioSink();

        if (aSink) {
            gchar *deviceDescription = NULL;

            if (GST_IS_PROPERTY_PROBE(aSink) && gst_property_probe_get_property( GST_PROPERTY_PROBE(aSink), "device" ) ) {
                g_object_set (G_OBJECT(aSink), "device", gstId.constData(), (const char*)NULL);
                g_object_get (G_OBJECT(aSink), "device-name", &deviceDescription, (const char*)NULL);
                description = QByteArray(deviceDescription);
                g_free (deviceDescription);
                gst_element_set_state(aSink, GST_STATE_NULL);
                gst_object_unref (aSink);
            }
        }
    }
}

DeviceManager::DeviceManager(Backend *backend)
        : QObject(backend)
        , m_backend(backend)
        , m_audioDeviceCounter(0)
{
    QSettings settings(QLatin1String("Trolltech"));
    settings.beginGroup(QLatin1String("Qt"));

    PulseSupport *pulse = PulseSupport::getInstance();
    m_audioSink = qgetenv("PHONON_GST_AUDIOSINK");
    if (m_audioSink.isEmpty()) {
        m_audioSink = settings.value(QLatin1String("audiosink"), "Auto").toByteArray().toLower();
        if (m_audioSink == "auto" && pulse->isActive())
            m_audioSink = "pulsesink";
    }
    if ("pulsesink" != m_audioSink)
        pulse->enable(false);

    m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE");
    if (m_videoSinkWidget.isEmpty()) {
        m_videoSinkWidget = settings.value(QLatin1String("videomode"), "Auto").toByteArray().toLower();
    }

    if (m_backend->isValid())
        updateDeviceList();
}

DeviceManager::~DeviceManager()
{
    m_audioDeviceList.clear();
}

/***
* Returns a Gst Audiosink based on GNOME configuration settings,
* or 0 if the element is not available.
*/
GstElement *DeviceManager::createGNOMEAudioSink(Category category)
{
    GstElement *sink = gst_element_factory_make ("gconfaudiosink", NULL);

    if (sink) {

        // set profile property on the gconfaudiosink to "music and movies"
        if (g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "profile")) {
            switch (category) {
            case NotificationCategory:
                g_object_set (G_OBJECT (sink), "profile", 0, (const char*)NULL); // 0 = 'sounds'
                break;
            case CommunicationCategory:
                g_object_set (G_OBJECT (sink), "profile", 2, (const char*)NULL); // 2 = 'chat'
                break;
            default:
                g_object_set (G_OBJECT (sink), "profile", 1, (const char*)NULL); // 1 = 'music and movies'
                break;
            }
        }
    }
    return sink;
}

bool DeviceManager::canOpenDevice(GstElement *element) const
{
    if (!element)
        return false;

    if (gst_element_set_state(element, GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS)
        return true;

    const QList<QByteArray> &list = GstHelper::extractProperties(element, "device");
    foreach (const QByteArray &gstId, list) {
        GstHelper::setProperty(element, "device", gstId);
        if (gst_element_set_state(element, GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS) {
            return true;
        }
    }
    // FIXME: the above can still fail for a valid alsasink because list only contains entries of
    // the form "hw:X,Y". Would be better to use "default:X" or "dmix:X,Y"

    gst_element_set_state(element, GST_STATE_NULL);
    return false;
}

/*
*
* Returns a GstElement with a valid audio sink
* based on the current value of PHONON_GSTREAMER_DRIVER
*
* Allowed values are auto (default), alsa, oss, arts and ess
* does not exist
*
* If no real sound sink is available a fakesink will be returned
*/
GstElement *DeviceManager::createAudioSink(Category category)
{
    GstElement *sink = 0;

    if (m_backend && m_backend->isValid())
    {
        if (m_audioSink == "auto") //this is the default value
        {
            //### TODO : get equivalent KDE settings here

            if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {
                sink = createGNOMEAudioSink(category);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using gconf audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }

#ifdef USE_ALSASINK2
            if (!sink) {
                sink = gst_element_factory_make ("_k_alsasink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using alsa2 audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }
#endif

            if (!sink) {
                sink = gst_element_factory_make ("alsasink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using alsa audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }

            if (!sink) {
                sink = gst_element_factory_make ("autoaudiosink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using auto audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }

            if (!sink) {
                sink = gst_element_factory_make ("osssink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using oss audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }
        } else if (m_audioSink == "fake") {
            //do nothing as a fakesink will be created by default
        } else if (m_audioSink == "artssink") {
            sink = GST_ELEMENT(g_object_new(arts_sink_get_type(), NULL));
        } else if (!m_audioSink.isEmpty()) { //Use a custom sink
            sink = gst_element_factory_make (m_audioSink, NULL);
            if (canOpenDevice(sink))
                m_backend->logMessage(QString("AudioOutput using %0").arg(QString::fromUtf8(m_audioSink)));
            else if (sink) {
                gst_object_unref(sink);
                sink = 0;
            }
        }
    }

    if (!sink) { //no suitable sink found so we'll make a fake one
        sink = gst_element_factory_make("fakesink", NULL);
        if (sink) {
            m_backend->logMessage("AudioOutput Using fake audio sink");
            //without sync the sink will pull the pipeline as fast as the CPU allows
            g_object_set (G_OBJECT (sink), "sync", TRUE, (const char*)NULL);
        }
    }
    Q_ASSERT(sink);
    return sink;
}

#ifndef QT_NO_PHONON_VIDEO
AbstractRenderer *DeviceManager::createVideoRenderer(VideoWidget *parent)
{
#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES)
    if (m_videoSinkWidget == "opengl") {
        return new GLRenderer(parent);
    } else
#endif
    if (m_videoSinkWidget == "software") {
        return new WidgetRenderer(parent);
    }
#ifndef Q_WS_QWS
    else if (m_videoSinkWidget == "xwindow") {
        return new X11Renderer(parent);
    } else {
        GstElementFactory *srcfactory = gst_element_factory_find("ximagesink");
        if (srcfactory) {
            return new X11Renderer(parent);
        }
    }
#endif
    return new WidgetRenderer(parent);
}
#endif //QT_NO_PHONON_VIDEO

/**
 * Allocate a device id for a new audio device
 */
int DeviceManager::allocateDeviceId()
{
    return m_audioDeviceCounter++;
}

/**
 * Returns a positive device id or -1 if device does not exist
 *
 * The gstId is typically in the format hw:1,0
 */
int DeviceManager::deviceId(const QByteArray &gstId) const
{
    for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
        if (m_audioDeviceList[i].gstId == gstId) {
            return m_audioDeviceList[i].id;
        }
    }
    return -1;
}

/**
 * Returns a gstId or "default" if device does not exist
 *
 * The gstId is typically in the format hw:1,0
 */
const QByteArray DeviceManager::gstId(int deviceId)
{
    if (!PulseSupport::getInstance()->isActive()) {
        AudioDevice *ad = audioDevice(deviceId);
        if (ad)
            return QByteArray(ad->gstId);
    }
    return QByteArray("default");
}

/**
* Get the AudioDevice for a given device id
*/
AudioDevice* DeviceManager::audioDevice(int id)
{
    for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
        if (m_audioDeviceList[i].id == id)
            return &m_audioDeviceList[i];
    }
    return NULL;
}

/**
 * Updates the current list of active devices
 */
void DeviceManager::updateDeviceList()
{
    //fetch list of current devices
    GstElement *audioSink= createAudioSink();

    QList<QByteArray> list;

    if (audioSink) {
        if (!PulseSupport::getInstance()->isActive()) {
            // If we're using pulse, the PulseSupport class takes care of things for us.
            list = GstHelper::extractProperties(audioSink, "device");
            list.prepend("default");
        }

        for (int i = 0 ; i < list.size() ; ++i) {
            QByteArray gstId = list.at(i);
            if (deviceId(gstId) == -1) {
                // This is a new device, add it
                m_audioDeviceList.append(AudioDevice(this, gstId));
                emit deviceAdded(deviceId(gstId));
                m_backend->logMessage(QString("Found new audio device %0").arg(QString::fromUtf8(gstId)), Backend::Debug, this);
            }
        }

        if (list.size() < m_audioDeviceList.size()) {
            //a device was removed
            for (int i = m_audioDeviceList.size() -1 ; i >= 0 ; --i) {
                QByteArray currId = m_audioDeviceList[i].gstId;
                bool found = false;
                for (int k = list.size() -1  ; k >= 0 ; --k) {
                    if (currId == list[k]) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    m_backend->logMessage(QString("Audio device lost %0").arg(QString::fromUtf8(currId)), Backend::Debug, this);
                    emit deviceRemoved(deviceId(currId));
                    m_audioDeviceList.removeAt(i);
                }
            }
        }
    }

    gst_element_set_state (audioSink, GST_STATE_NULL);
    gst_object_unref (audioSink);
}

/**
  * Returns a list of hardware id usable by gstreamer [i.e hw:1,0]
  */
const QList<AudioDevice> DeviceManager::audioOutputDevices() const
{
    return m_audioDeviceList;
}

}
}

QT_END_NAMESPACE
<commit_msg>gstreamer: Rejig the PulseAudio detection and handling a little.<commit_after>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

    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 or 3 of the License.

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

    You should have received a copy of the GNU Lesser General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <gst/interfaces/propertyprobe.h>
#include "devicemanager.h"
#include "backend.h"
#include "gsthelper.h"
#include "videowidget.h"
#include "glrenderer.h"
#include "widgetrenderer.h"
#include "x11renderer.h"
#include "artssink.h"
#include "pulsesupport.h"

#ifdef USE_ALSASINK2
#include "alsasink2.h"
#endif

/*
 * This class manages the list of currently
 * active output devices
 */

QT_BEGIN_NAMESPACE

namespace Phonon
{
namespace Gstreamer
{

AudioDevice::AudioDevice(DeviceManager *manager, const QByteArray &gstId)
        : gstId(gstId)
{
    // This should never be called when PulseAudio is active.
    Q_ASSERT(!PulseSupport::getInstance()->isActive());

    id = manager->allocateDeviceId();
    icon = "audio-card";

    //get name from device
    if (gstId == "default") {
        description = "Default audio device";
    } else {
        GstElement *aSink= manager->createAudioSink();

        if (aSink) {
            gchar *deviceDescription = NULL;

            if (GST_IS_PROPERTY_PROBE(aSink) && gst_property_probe_get_property( GST_PROPERTY_PROBE(aSink), "device" ) ) {
                g_object_set (G_OBJECT(aSink), "device", gstId.constData(), (const char*)NULL);
                g_object_get (G_OBJECT(aSink), "device-name", &deviceDescription, (const char*)NULL);
                description = QByteArray(deviceDescription);
                g_free (deviceDescription);
                gst_element_set_state(aSink, GST_STATE_NULL);
                gst_object_unref (aSink);
            }
        }
    }
}

DeviceManager::DeviceManager(Backend *backend)
        : QObject(backend)
        , m_backend(backend)
        , m_audioDeviceCounter(0)
{
    QSettings settings(QLatin1String("Trolltech"));
    settings.beginGroup(QLatin1String("Qt"));

    PulseSupport *pulse = PulseSupport::getInstance();
    m_audioSink = qgetenv("PHONON_GST_AUDIOSINK");
    if (m_audioSink.isEmpty())
        m_audioSink = settings.value(QLatin1String("audiosink"), "Auto").toByteArray().toLower();

    if ("pulsesink" == m_audioSink && !pulse->isActive()) {
        // If pulsesink is specifically requested, but not active, then
        // fall back to auto.
        m_audioSink = "auto";
    } else if (m_audioSink == "auto" && pulse->isActive()) {
        // We favour specific PA support if it's active and we're in 'auto' mode
        // (although it may still be disabled if the pipeline cannot be made)
        m_audioSink = "pulsesink";
    } else if (m_audioSink != "pulsesink") {
        // Otherwise, PA should not be used.
        pulse->enable(false);
    }

    m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE");
    if (m_videoSinkWidget.isEmpty()) {
        m_videoSinkWidget = settings.value(QLatin1String("videomode"), "Auto").toByteArray().toLower();
    }

    if (m_backend->isValid())
        updateDeviceList();
}

DeviceManager::~DeviceManager()
{
    m_audioDeviceList.clear();
}

/***
* Returns a Gst Audiosink based on GNOME configuration settings,
* or 0 if the element is not available.
*/
GstElement *DeviceManager::createGNOMEAudioSink(Category category)
{
    GstElement *sink = gst_element_factory_make ("gconfaudiosink", NULL);

    if (sink) {

        // set profile property on the gconfaudiosink to "music and movies"
        if (g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "profile")) {
            switch (category) {
            case NotificationCategory:
                g_object_set (G_OBJECT (sink), "profile", 0, (const char*)NULL); // 0 = 'sounds'
                break;
            case CommunicationCategory:
                g_object_set (G_OBJECT (sink), "profile", 2, (const char*)NULL); // 2 = 'chat'
                break;
            default:
                g_object_set (G_OBJECT (sink), "profile", 1, (const char*)NULL); // 1 = 'music and movies'
                break;
            }
        }
    }
    return sink;
}

bool DeviceManager::canOpenDevice(GstElement *element) const
{
    if (!element)
        return false;

    if (gst_element_set_state(element, GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS)
        return true;

    const QList<QByteArray> &list = GstHelper::extractProperties(element, "device");
    foreach (const QByteArray &gstId, list) {
        GstHelper::setProperty(element, "device", gstId);
        if (gst_element_set_state(element, GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS) {
            return true;
        }
    }
    // FIXME: the above can still fail for a valid alsasink because list only contains entries of
    // the form "hw:X,Y". Would be better to use "default:X" or "dmix:X,Y"

    gst_element_set_state(element, GST_STATE_NULL);
    return false;
}

/*
*
* Returns a GstElement with a valid audio sink
* based on the current value of PHONON_GSTREAMER_DRIVER
*
* Allowed values are auto (default), alsa, oss, arts and ess
* does not exist
*
* If no real sound sink is available a fakesink will be returned
*/
GstElement *DeviceManager::createAudioSink(Category category)
{
    GstElement *sink = 0;

    if (m_backend && m_backend->isValid())
    {
        if (m_audioSink == "auto") //this is the default value
        {
            //### TODO : get equivalent KDE settings here

            if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {
                sink = createGNOMEAudioSink(category);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using gconf audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }

#ifdef USE_ALSASINK2
            if (!sink) {
                sink = gst_element_factory_make ("_k_alsasink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using alsa2 audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }
#endif

            if (!sink) {
                sink = gst_element_factory_make ("alsasink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using alsa audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }

            if (!sink) {
                sink = gst_element_factory_make ("autoaudiosink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using auto audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }

            if (!sink) {
                sink = gst_element_factory_make ("osssink", NULL);
                if (canOpenDevice(sink))
                    m_backend->logMessage("AudioOutput using oss audio sink");
                else if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
            }
        } else if (m_audioSink == "fake") {
            //do nothing as a fakesink will be created by default
        } else if (m_audioSink == "artssink") {
            sink = GST_ELEMENT(g_object_new(arts_sink_get_type(), NULL));
        } else if (!m_audioSink.isEmpty()) { //Use a custom sink
            sink = gst_element_factory_make (m_audioSink, NULL);
            if (canOpenDevice(sink))
                m_backend->logMessage(QString("AudioOutput using %0").arg(QString::fromUtf8(m_audioSink)));
            else {
                if (sink) {
                    gst_object_unref(sink);
                    sink = 0;
                }
                if ("pulsesink" == m_audioSink) {
                    // We've tried to use PulseAudio support, but the GST plugin
                    // doesn't exits. Let's try again, but not use PA support this time.
                    m_backend->logMessage("PulseAudio support failed. Falling back to 'auto'");
                    PulseSupport::getInstance()->enable(false);
                    m_audioSink = "auto";
                    sink = createAudioSink();
                }
            }
        }
    }

    if (!sink) { //no suitable sink found so we'll make a fake one
        sink = gst_element_factory_make("fakesink", NULL);
        if (sink) {
            m_backend->logMessage("AudioOutput Using fake audio sink");
            //without sync the sink will pull the pipeline as fast as the CPU allows
            g_object_set (G_OBJECT (sink), "sync", TRUE, (const char*)NULL);
        }
    }
    Q_ASSERT(sink);
    return sink;
}

#ifndef QT_NO_PHONON_VIDEO
AbstractRenderer *DeviceManager::createVideoRenderer(VideoWidget *parent)
{
#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES)
    if (m_videoSinkWidget == "opengl") {
        return new GLRenderer(parent);
    } else
#endif
    if (m_videoSinkWidget == "software") {
        return new WidgetRenderer(parent);
    }
#ifndef Q_WS_QWS
    else if (m_videoSinkWidget == "xwindow") {
        return new X11Renderer(parent);
    } else {
        GstElementFactory *srcfactory = gst_element_factory_find("ximagesink");
        if (srcfactory) {
            return new X11Renderer(parent);
        }
    }
#endif
    return new WidgetRenderer(parent);
}
#endif //QT_NO_PHONON_VIDEO

/**
 * Allocate a device id for a new audio device
 */
int DeviceManager::allocateDeviceId()
{
    return m_audioDeviceCounter++;
}

/**
 * Returns a positive device id or -1 if device does not exist
 *
 * The gstId is typically in the format hw:1,0
 */
int DeviceManager::deviceId(const QByteArray &gstId) const
{
    for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
        if (m_audioDeviceList[i].gstId == gstId) {
            return m_audioDeviceList[i].id;
        }
    }
    return -1;
}

/**
 * Returns a gstId or "default" if device does not exist
 *
 * The gstId is typically in the format hw:1,0
 */
const QByteArray DeviceManager::gstId(int deviceId)
{
    if (!PulseSupport::getInstance()->isActive()) {
        AudioDevice *ad = audioDevice(deviceId);
        if (ad)
            return QByteArray(ad->gstId);
    }
    return QByteArray("default");
}

/**
* Get the AudioDevice for a given device id
*/
AudioDevice* DeviceManager::audioDevice(int id)
{
    for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
        if (m_audioDeviceList[i].id == id)
            return &m_audioDeviceList[i];
    }
    return NULL;
}

/**
 * Updates the current list of active devices
 */
void DeviceManager::updateDeviceList()
{
    //fetch list of current devices
    GstElement *audioSink= createAudioSink();

    QList<QByteArray> list;

    if (audioSink) {
        if (!PulseSupport::getInstance()->isActive()) {
            // If we're using pulse, the PulseSupport class takes care of things for us.
            list = GstHelper::extractProperties(audioSink, "device");
            list.prepend("default");
        }

        for (int i = 0 ; i < list.size() ; ++i) {
            QByteArray gstId = list.at(i);
            if (deviceId(gstId) == -1) {
                // This is a new device, add it
                m_audioDeviceList.append(AudioDevice(this, gstId));
                emit deviceAdded(deviceId(gstId));
                m_backend->logMessage(QString("Found new audio device %0").arg(QString::fromUtf8(gstId)), Backend::Debug, this);
            }
        }

        if (list.size() < m_audioDeviceList.size()) {
            //a device was removed
            for (int i = m_audioDeviceList.size() -1 ; i >= 0 ; --i) {
                QByteArray currId = m_audioDeviceList[i].gstId;
                bool found = false;
                for (int k = list.size() -1  ; k >= 0 ; --k) {
                    if (currId == list[k]) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    m_backend->logMessage(QString("Audio device lost %0").arg(QString::fromUtf8(currId)), Backend::Debug, this);
                    emit deviceRemoved(deviceId(currId));
                    m_audioDeviceList.removeAt(i);
                }
            }
        }
    }

    gst_element_set_state (audioSink, GST_STATE_NULL);
    gst_object_unref (audioSink);
}

/**
  * Returns a list of hardware id usable by gstreamer [i.e hw:1,0]
  */
const QList<AudioDevice> DeviceManager::audioOutputDevices() const
{
    return m_audioDeviceList;
}

}
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#include "BluPrivatePCH.h"
#include "Runtime/UMG/Public/Blueprint/WidgetLayoutLibrary.h"

UBluEye::UBluEye(const class FObjectInitializer& PCIP)
	: Super(PCIP)
{

	Width = 800;
	Height = 600;

	bIsTransparent = false;

}

void UBluEye::init()
{

	browserSettings.universal_access_from_file_urls = STATE_ENABLED;
	browserSettings.file_access_from_file_urls = STATE_ENABLED;

	info.width = Width;
	info.height = Height;

	// Set transparant option
	info.SetAsWindowless(NULL, bIsTransparent);

	renderer = new RenderHandler(Width, Height, this);
	g_handler = new BrowserClient(renderer);
	browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL);

	// Setup JS event emitter
	g_handler->SetEventEmitter(&ScriptEventEmitter);

	UE_LOG(LogBlu, Log, TEXT("Component Initialized"));
	CefString str = *DefaultURL;
	UE_LOG(LogBlu, Log, TEXT("Loading URL: %s"), *DefaultURL);

	// Load the URL
	browser->GetMainFrame()->LoadURL(*DefaultURL);
	ResetTexture();

}

void UBluEye::ResetTexture()
{

	// Here we init the texture to its initial state
	DestroyTexture();

	// init the new Texture2D
	Texture = UTexture2D::CreateTransient(Width, Height);
	Texture->AddToRoot();
	Texture->UpdateResource();

	ResetMatInstance();

}

void UBluEye::DestroyTexture()
{
	// Here we destory the texture and its resource
	if (Texture)
	{
		Texture->RemoveFromRoot();

		if (Texture->Resource)
		{
			BeginReleaseResource(Texture->Resource);
			FlushRenderingCommands();
		}

		Texture->MarkPendingKill();
		Texture = nullptr;
	}
}

void UBluEye::TextureUpdate(const void *buffer)
{
	if (!browser || !bEnabled)
	{
		UE_LOG(LogBlu, Warning, TEXT("NO BROWSER ACCESS OR NOT ENABLED"))
		return;
	}

	if (Texture && Texture->Resource)
	{

		// Is our texture ready?
		auto ref = static_cast<FTexture2DResource*>(Texture->Resource)->GetTexture2DRHI();
		if (!ref)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO REF"))
				return;
		}

		if (buffer == nullptr)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO TEXTDATA"))
				return;
		}

		const size_t size = Width * Height * sizeof(uint32);

		// @TODO This is a bit heavy to keep reallocating/deallocating, but not a big deal. Maybe we can ping pong between buffers instead.
		TArray<uint32> ViewBuffer;
		ViewBuffer.Init(Width * Height);
		FMemory::Memcpy(ViewBuffer.GetData(), buffer, size);

		TextureDataPtr dataPtr = MakeShareable(new TextureData);

		dataPtr->SetRawData(Width, Height, sizeof(uint32), ViewBuffer);

		// Clean up from the per-render
		ViewBuffer.Empty();
		buffer = 0;

		ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
			TextureData,
			TextureDataPtr, ImageData, dataPtr,
			FTexture2DRHIRef, TargetTexture, ref,
			const size_t, DataSize, size,
			{
			uint32 stride = 0;
			void* MipData = GDynamicRHI->RHILockTexture2D(TargetTexture, 0, RLM_WriteOnly, stride, false);

			if (MipData)
			{
				FMemory::Memcpy(MipData, ImageData->GetRawBytesPtr(), ImageData->GetDataSize());
				GDynamicRHI->RHIUnlockTexture2D(TargetTexture, 0, false);
			}

			ImageData.Reset();
		});

	}
	else {
		UE_LOG(LogBlu, Warning, TEXT("no Texture or Texture->resource"))
	}

}

void UBluEye::ExecuteJS(FString code)
{
	CefString codeStr = *code;
	UE_LOG(LogBlu, Log, TEXT("Execute JS: %s"), *code)
	browser->GetMainFrame()->ExecuteJavaScript(codeStr, "", 0);
	// create an event function that can be called from JS
}

void UBluEye::TriggerMouseMove(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	// UE_LOG(LogBlu, Warning, TEXT("Mouse Update pos: %s"), *pos.ToString())

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
}

void UBluEye::TriggerLeftClick(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	//browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);

	UE_LOG(LogBlu, Warning, TEXT("Left Click %s"), *pos.ToString())
}

void UBluEye::TriggerRightClick(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	//browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 1);

	UE_LOG(LogBlu, Warning, TEXT("Right click %s"), *pos.ToString())
}

void UBluEye::KeyDown(FKeyEvent InKeyEvent)
{

	CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("key_event");
	msg->GetArgumentList()->SetInt(0, InKeyEvent.GetKeyCode());
	msg->GetArgumentList()->SetInt(1, InKeyEvent.GetCharacter());

	// Check key mod flags!
	// We'll check alt first
	if (InKeyEvent.IsAltDown())
	{
		msg->GetArgumentList()->SetBool(0, true);
	} else {
		msg->GetArgumentList()->SetBool(0, false);
	}

	// Then control takes priority
	if (InKeyEvent.IsControlDown())
	{
		msg->GetArgumentList()->SetBool(1, true);
	} else {
		msg->GetArgumentList()->SetBool(1, false);
	}

	// Shift should be checked last, more important!
	if (InKeyEvent.IsShiftDown())
	{
		msg->GetArgumentList()->SetBool(2, true);
	} else {
		msg->GetArgumentList()->SetBool(2, false);
	}

	browser->SendProcessMessage(PID_RENDERER, msg);

	UE_LOG(LogBlu, Warning, TEXT("SEND KEY EVENT"))
}

UTexture2D* UBluEye::GetTexture() const
{
	check(Texture)
	return Texture;
}

UMaterialInstanceDynamic* UBluEye::GetMaterialInstance() const
{
	return MaterialInstance;
}

void UBluEye::ResetMatInstance()
{
	if (!Texture || !BaseMaterial || TextureParameterName.IsNone())
	{
		return;
	}

	// Create material instance
	if (!MaterialInstance)
	{
		MaterialInstance = UMaterialInstanceDynamic::Create(BaseMaterial, NULL);
		if (!MaterialInstance)
		{
			UE_LOG(LogBlu, Warning, TEXT("UI Material instance can't be created"));
			return;
		}
	}

	// Check again, we must have material instance
	if (!MaterialInstance)
	{
		UE_LOG(LogBlu, Error, TEXT("UI Material instance wasn't created"));
		return;
	}

	// Check we have desired parameter
	UTexture* Tex = nullptr;
	if (!MaterialInstance->GetTextureParameterValue(TextureParameterName, Tex))
	{
		UE_LOG(LogBlu, Warning, TEXT("UI Material instance Texture parameter not found"));
		return;
	}

	MaterialInstance->SetTextureParameterValue(TextureParameterName, GetTexture());
}

void UBluEye::BeginDestroy()
{
	if (browser)
	{
		browser->GetHost()->CloseBrowser(true);
	}

	DestroyTexture();
	Super::BeginDestroy();
}<commit_msg>remove unused include<commit_after>#include "BluPrivatePCH.h"

UBluEye::UBluEye(const class FObjectInitializer& PCIP)
	: Super(PCIP)
{

	Width = 800;
	Height = 600;

	bIsTransparent = false;

}

void UBluEye::init()
{

	browserSettings.universal_access_from_file_urls = STATE_ENABLED;
	browserSettings.file_access_from_file_urls = STATE_ENABLED;

	info.width = Width;
	info.height = Height;

	// Set transparant option
	info.SetAsWindowless(NULL, bIsTransparent);

	renderer = new RenderHandler(Width, Height, this);
	g_handler = new BrowserClient(renderer);
	browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL);

	// Setup JS event emitter
	g_handler->SetEventEmitter(&ScriptEventEmitter);

	UE_LOG(LogBlu, Log, TEXT("Component Initialized"));
	CefString str = *DefaultURL;
	UE_LOG(LogBlu, Log, TEXT("Loading URL: %s"), *DefaultURL);

	// Load the URL
	browser->GetMainFrame()->LoadURL(*DefaultURL);
	ResetTexture();

}

void UBluEye::ResetTexture()
{

	// Here we init the texture to its initial state
	DestroyTexture();

	// init the new Texture2D
	Texture = UTexture2D::CreateTransient(Width, Height);
	Texture->AddToRoot();
	Texture->UpdateResource();

	ResetMatInstance();

}

void UBluEye::DestroyTexture()
{
	// Here we destory the texture and its resource
	if (Texture)
	{
		Texture->RemoveFromRoot();

		if (Texture->Resource)
		{
			BeginReleaseResource(Texture->Resource);
			FlushRenderingCommands();
		}

		Texture->MarkPendingKill();
		Texture = nullptr;
	}
}

void UBluEye::TextureUpdate(const void *buffer)
{
	if (!browser || !bEnabled)
	{
		UE_LOG(LogBlu, Warning, TEXT("NO BROWSER ACCESS OR NOT ENABLED"))
		return;
	}

	if (Texture && Texture->Resource)
	{

		// Is our texture ready?
		auto ref = static_cast<FTexture2DResource*>(Texture->Resource)->GetTexture2DRHI();
		if (!ref)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO REF"))
				return;
		}

		if (buffer == nullptr)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO TEXTDATA"))
				return;
		}

		const size_t size = Width * Height * sizeof(uint32);

		// @TODO This is a bit heavy to keep reallocating/deallocating, but not a big deal. Maybe we can ping pong between buffers instead.
		TArray<uint32> ViewBuffer;
		ViewBuffer.Init(Width * Height);
		FMemory::Memcpy(ViewBuffer.GetData(), buffer, size);

		TextureDataPtr dataPtr = MakeShareable(new TextureData);

		dataPtr->SetRawData(Width, Height, sizeof(uint32), ViewBuffer);

		// Clean up from the per-render
		ViewBuffer.Empty();
		buffer = 0;

		ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
			TextureData,
			TextureDataPtr, ImageData, dataPtr,
			FTexture2DRHIRef, TargetTexture, ref,
			const size_t, DataSize, size,
			{
			uint32 stride = 0;
			void* MipData = GDynamicRHI->RHILockTexture2D(TargetTexture, 0, RLM_WriteOnly, stride, false);

			if (MipData)
			{
				FMemory::Memcpy(MipData, ImageData->GetRawBytesPtr(), ImageData->GetDataSize());
				GDynamicRHI->RHIUnlockTexture2D(TargetTexture, 0, false);
			}

			ImageData.Reset();
		});

	}
	else {
		UE_LOG(LogBlu, Warning, TEXT("no Texture or Texture->resource"))
	}

}

void UBluEye::ExecuteJS(FString code)
{
	CefString codeStr = *code;
	UE_LOG(LogBlu, Log, TEXT("Execute JS: %s"), *code)
	browser->GetMainFrame()->ExecuteJavaScript(codeStr, "", 0);
	// create an event function that can be called from JS
}

void UBluEye::TriggerMouseMove(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	// UE_LOG(LogBlu, Warning, TEXT("Mouse Update pos: %s"), *pos.ToString())

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
}

void UBluEye::TriggerLeftClick(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	//browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);

	UE_LOG(LogBlu, Warning, TEXT("Left Click %s"), *pos.ToString())
}

void UBluEye::TriggerRightClick(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	//browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);
	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 1);

	UE_LOG(LogBlu, Warning, TEXT("Right click %s"), *pos.ToString())
}

void UBluEye::KeyDown(FKeyEvent InKeyEvent)
{

	CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("key_event");
	msg->GetArgumentList()->SetInt(0, InKeyEvent.GetKeyCode());
	msg->GetArgumentList()->SetInt(1, InKeyEvent.GetCharacter());

	// Check key mod flags!
	// We'll check alt first
	if (InKeyEvent.IsAltDown())
	{
		msg->GetArgumentList()->SetBool(0, true);
	} else {
		msg->GetArgumentList()->SetBool(0, false);
	}

	// Then control takes priority
	if (InKeyEvent.IsControlDown())
	{
		msg->GetArgumentList()->SetBool(1, true);
	} else {
		msg->GetArgumentList()->SetBool(1, false);
	}

	// Shift should be checked last, more important!
	if (InKeyEvent.IsShiftDown())
	{
		msg->GetArgumentList()->SetBool(2, true);
	} else {
		msg->GetArgumentList()->SetBool(2, false);
	}

	browser->SendProcessMessage(PID_RENDERER, msg);

	UE_LOG(LogBlu, Warning, TEXT("SEND KEY EVENT"))
}

UTexture2D* UBluEye::GetTexture() const
{
	check(Texture)
	return Texture;
}

UMaterialInstanceDynamic* UBluEye::GetMaterialInstance() const
{
	return MaterialInstance;
}

void UBluEye::ResetMatInstance()
{
	if (!Texture || !BaseMaterial || TextureParameterName.IsNone())
	{
		return;
	}

	// Create material instance
	if (!MaterialInstance)
	{
		MaterialInstance = UMaterialInstanceDynamic::Create(BaseMaterial, NULL);
		if (!MaterialInstance)
		{
			UE_LOG(LogBlu, Warning, TEXT("UI Material instance can't be created"));
			return;
		}
	}

	// Check again, we must have material instance
	if (!MaterialInstance)
	{
		UE_LOG(LogBlu, Error, TEXT("UI Material instance wasn't created"));
		return;
	}

	// Check we have desired parameter
	UTexture* Tex = nullptr;
	if (!MaterialInstance->GetTextureParameterValue(TextureParameterName, Tex))
	{
		UE_LOG(LogBlu, Warning, TEXT("UI Material instance Texture parameter not found"));
		return;
	}

	MaterialInstance->SetTextureParameterValue(TextureParameterName, GetTexture());
}

void UBluEye::BeginDestroy()
{
	if (browser)
	{
		browser->GetHost()->CloseBrowser(true);
	}

	DestroyTexture();
	Super::BeginDestroy();
}<|endoftext|>


<commit_before>
// Arnaud Desitter

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iostream.h>

// for stat
#include <sys/types.h>
#include <sys/stat.h>

// include files from $EXPLORERHOME/include
#include<cx/UI.h>
#include<cx/Pyramid.h>
#include<cx/cxPyramid.api.h>
#include<cx/DataAccess.h>
#include<cx/DataOps.h>
#include<cx/PortAccess.h>

// Iris Explorer user function
#include <ReadChild.uf.h>

// local
#include <cxSmartPtr.h>
#include <readChildData.h>

// type of floating point for lattice
#define FLOAT float
#define CXFLOAT cx_prim_float

//#define DEBUG1

// extract a pointer to string hold by the "File Name" widget
static
const char *GetFileName(void){
  cxErrorCode ec = cx_err_none;
  int port = cxInputPortOpen("File Name");
  assert( -1 != port );
  cxParameter* Wdgt = static_cast<cxParameter*>(cxInputDataGet(port));
  assert(  cx_param_string == cxParameterTypeGet( Wdgt, &ec ) );

  return *( static_cast<char**>(cxParameterValueGet( Wdgt, &ec )) );
}

// compute and allocate a filename with the last suffix stripped
static
int IsFileNameValid(const char *filename){
  if (filename == NULL || 0 == strcmp(filename,"")) {
    cerr << "Filename is not set." << endl;
    return -1;
  }
  struct stat statbuf;
  if (0 != stat(filename,&statbuf)){
    cerr << "Filename is not readable." << endl;
    return -1;
  }
  if (! S_ISREG(statbuf.st_mode)){
    cerr << "Filename is invalid." << endl;
    return -1;
  }
  return 0;
}

// compute and allocate a filename with the last suffix stripped
static
int myBasename(const char *filename, char **basename){

  const size_t len_f = strlen(filename);
  // find location of the last '.' before a '/' if exist.
  int index_p = -1;
  for(size_t j = len_f; j != 0; j--){
    if (filename[j] == '/' ) break;
    if (filename[j] == '.' ) {
      index_p = j;
      break;
    }
  }
  if (index_p == -1 || index_p == 0){
    return -1;
  }

  char *b = new char[index_p+1];
  strncpy(b, filename, index_p);
  b[index_p] = '\0';
  *basename = b;
  return 0;
}

// test existence of files
static
int stat_file(const char* b){
  struct stat statbuf;
  if (0 != stat(b,&statbuf)){
    cerr << b << " is not readable." << endl;
    return -1;
  }
  if (! S_ISREG(statbuf.st_mode)){
    cerr << b << " is invalid." << endl;
    return -1;
  }
  return 0;
}

int testBasename(const char *basename){
  if (basename == NULL || 0 == strcmp(basename,"")) return -1;

  const size_t len_b = strlen(basename);
  char *b = new char[len_b+10];
  strcpy(b,basename);
  // test for .nodes

  assert(b[len_b] == '\0'); // paranoid !
  b[len_b] = '\0';
  strcat(b,".nodes");
  if (0 != stat_file(b))
    goto fail;
  b[len_b] = '\0';
  strcat(b,".tri");
  if (0 != stat_file(b))
    goto fail;
  b[len_b] = '\0';
  strcat(b,".z");
  if (0 != stat_file(b))
    goto fail;

  delete [] b;
  return 0;
 fail:
  delete [] b;
  return -1;
}

void ReadChild
(
 int nStep,
 int TypeVariable,
 cxPyramid    **Pyr2D,
 cxParameter  **currentTime
 ) {
#ifdef DEBUG1
  cout << "Entering main function" << endl;
#endif
  //-----------------------------------------------------------------
  // Extract File Name
  char *basename(0);
  {
    char const * const filename = GetFileName();
#ifdef DEBUG1
    cout << "FileName=" << filename << endl;
#endif
    if (0 != IsFileNameValid(filename))
      return;
    if (0 != myBasename(filename, &basename)){
      cerr << "Filename does not have a suffix." << endl;
      return;
    }
#ifdef DEBUG1
    cout << "BaseName=" << basename << endl;
#endif
    if (0 != testBasename(basename))
      return;
  }
  //-----------------------------------------------------------------
  ReadChildData ChildData;
  try {
    if (!ChildData.LoadData(basename, nStep, TypeVariable)) {
      cerr << "Time step \"" << nStep << "\" does not exist." << endl;
      delete [] basename;
      return;
    }
  } catch (const BadFile &ex) {
    cerr << "Error when reading file \"" << ex.filename()
	 << "\": " << ex.ExceptionName()
	 << "." << endl;
    delete [] basename;
    return;
  } catch (...) {
    cerr << "A unkown exception occured during file processing." << endl;
    delete [] basename;
    return;
  }
  delete [] basename; basename = 0;
  const size_t npoints = ChildData.nnodes();
  const size_t nelem = ChildData.ntri();
  assert( npoints > 0 );
  assert( nelem > 0 );

#ifdef DEBUG1
  cout << "Data loaded." << endl;
#endif
  // set time
  *currentTime = cxParamDoubleNew(ChildData.currentTime());
  //-----------------------------------------------------------------
  // Pyramid building
  cxLattice_var baselat;                // base lattice
  cxConnection_var conn;                // elt2node connectivity
  cxPyramid_var Pyr2Dt;
  FLOAT *latcoord  = 0;                 // lattice coordinate buffer
  FLOAT *latdata  = 0;                  // lattice data buffer
  long *elem_  = 0;
  long *connec  = 0;
  cxErrorCode ec = cx_err_none;

  long nbn = npoints;   // nb of nodes
  const long nbe = nelem;     // nb of elements
  const long nbnve = 3*nelem; // nb of vertices
                              // 3 nodes per triangles

#ifdef DEBUG1
  cerr << "Nodes "    << nbn   << endl
       << "Elements " << nbe   << endl
       << "Vertices " << nbnve << endl;
#endif
  //-----------------------------------------------------------------
  // Allocate Explorer Type

  // Allocate base lattice
  baselat= cxLatNew(1,            /* 1D lattice */
		    &nbn,         /* where dims[] is nbne */
		    1,            /* 1 variables / node */
		    CXFLOAT,      /* type is float */
		    2,            /* number of coordinates / node */
		    // 3 for x,y,z
		    cx_coord_curvilinear /* curvilinear coordinates */
		    );
  if (cxDataAllocErrorGet()){
    cxModAlert("Error. Memory allocation failed for base lattice.");
    cxDataAllocErrorClear();
    return;
  }
  // Allocate pyramid
  Pyr2Dt = cxPyrNew(0);
  if (cxDataAllocErrorGet()){
    cxModAlert("Error. Memory allocation failed for Pyramid.");
    cxDataAllocErrorClear();
    return;
  }
  // Allocate connectivity
  conn = cxConnNew(nbe,nbnve);
  if (cxDataAllocErrorGet()){
    cxModAlert("Error. Memory allocation failed for connectivity");
    cxDataAllocErrorClear();
    return;
  }
  // Allocate and set Pyramid Dictionary
  long *iptr  = 0;
  {
    cxPyramidDictionary_var dict;
    dict = cxPyrDictDefault( 2 );         // triangle/quadrangle dict.
    if ( !dict ) {
      cxModAlert("Error while allocating dictionnary");
      cxDataAllocErrorClear();
      return;
    }
    cxPyramidDictionarySet(Pyr2Dt, dict, &ec );
    if ( cx_err_none != ec ){
      cxModAlert("Error while setting dictionnary");
      cxDataAllocErrorClear();
      return;
    } else {
      dict._retn();
    }
  }
  cxPyramidCompressionTypeSet(Pyr2Dt,cx_compress_unique, &ec);
  if ( cx_err_none != ec ){
    cxModAlert("Error during cxPyramidCompressionTypeSet.");
    cxDataAllocErrorClear();
    return;
  }
  iptr = (long *)cxPyramidCompressionIndexGet(Pyr2Dt, &ec);
  if ( cx_err_none != ec ){
    cxModAlert("Error during cxPyramidCompressionIndexGet.");
    cxDataAllocErrorClear();
    return;
  }
  iptr[0] = cx_pyramid_dict_triangle;

    //-----------------------------------------------------------------
    // Build and set base Lattice
    /* Fetch pointers and fill it with coordinates and data */
  {
    void *_latdata, *_latcoord;
    ec=cxLatPtrGet(baselat,
		   NULL,
		   &_latdata,
		   NULL,
		   &_latcoord
		   );
    latdata = static_cast<FLOAT *>(_latdata);
    latcoord = static_cast<FLOAT *>(_latcoord);
  }
  if ( cx_err_none != ec){
    cxModAlert("Error. base lattice corrupted.");
    cxDataAllocErrorClear();
    return;
  }

  {
    for(int inode=0;inode<nbn;inode++){
      latcoord[2*inode  ] = ChildData.x[inode];
      latcoord[2*inode+1] = ChildData.y[inode];
    }
  }
  {
    // Data
    for(int inode=0;inode<nbn;inode++){
      latdata[inode] = ChildData.z[inode];
    }
  }

  ec = cxPyrSet(Pyr2Dt,baselat);   /* set base lattice */
  if ( cx_err_none != ec){
    cxModAlert("Error during set base lattice.");
    cxDataAllocErrorClear();
    return;
  } else {
    baselat._retn();
  }

  //-----------------------------------------------------------------
  // Set Pyramid Layer and set base Lattice by recovering data from CORBA object

  ec = cxPyrLayerSet(Pyr2Dt,1,NULL,NULL); /* nullify first connectivity level */
  if ( cx_err_none != ec){
    cxModAlert("Error during cxPyrLayerSet.");
    cxDataAllocErrorClear();
    return;
  }

  /* Fetch pointers and set up the connections list */
  ec = cxConnPtrGet(conn,NULL,NULL,&elem_,&connec);
  if ( cx_err_none != ec){
    cxModAlert("Error during cxConnPtrGet.");
    cxDataAllocErrorClear();
    return;
  }
  // Recover data from CORBA object
  // Note: memcpy cannot safely be used (due to the integer sign)
  {
    // element to vertex connectivity table
    for(int ielem=0;ielem<nbe;ielem++){
      connec[3*ielem  ]= ChildData.p0[ielem];
      connec[3*ielem+1]= ChildData.p1[ielem];
      connec[3*ielem+2]= ChildData.p2[ielem];
    }
  }
  // build element to node table
  for(int ielem=0;ielem<(nbe+1);ielem++){
    elem_[ielem]= ielem * 3;  /* 3 nodes per elements */
  }

  ec = cxPyrLayerSet(Pyr2Dt,2,conn,NULL);
  if ( cx_err_none != ec){
    cxModAlert("Error during cxPyrLayerSet.");
    cxDataAllocErrorClear();
    return;
  } else {
    conn._retn();
  }

  //-----------------------------------------------------------------
  // Return the pyramid
  *Pyr2D = Pyr2Dt._retn();

  return;
}
<commit_msg>removed comments<commit_after>
// Arnaud Desitter

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iostream.h>

// for stat
#include <sys/types.h>
#include <sys/stat.h>

// include files from $EXPLORERHOME/include
#include<cx/UI.h>
#include<cx/Pyramid.h>
#include<cx/cxPyramid.api.h>
#include<cx/DataAccess.h>
#include<cx/DataOps.h>
#include<cx/PortAccess.h>

// Iris Explorer user function
#include <ReadChild.uf.h>

// local
#include <cxSmartPtr.h>
#include <readChildData.h>

// type of floating point for lattice
#define FLOAT float
#define CXFLOAT cx_prim_float

//#define DEBUG1

// extract a pointer to string hold by the "File Name" widget
static
const char *GetFileName(void){
  cxErrorCode ec = cx_err_none;
  int port = cxInputPortOpen("File Name");
  assert( -1 != port );
  cxParameter* Wdgt = static_cast<cxParameter*>(cxInputDataGet(port));
  assert(  cx_param_string == cxParameterTypeGet( Wdgt, &ec ) );

  return *( static_cast<char**>(cxParameterValueGet( Wdgt, &ec )) );
}

// compute and allocate a filename with the last suffix stripped
static
int IsFileNameValid(const char *filename){
  if (filename == NULL || 0 == strcmp(filename,"")) {
    cerr << "Filename is not set." << endl;
    return -1;
  }
  struct stat statbuf;
  if (0 != stat(filename,&statbuf)){
    cerr << "Filename is not readable." << endl;
    return -1;
  }
  if (! S_ISREG(statbuf.st_mode)){
    cerr << "Filename is invalid." << endl;
    return -1;
  }
  return 0;
}

// compute and allocate a filename with the last suffix stripped
static
int myBasename(const char *filename, char **basename){

  const size_t len_f = strlen(filename);
  // find location of the last '.' before a '/' if exist.
  int index_p = -1;
  for(size_t j = len_f; j != 0; j--){
    if (filename[j] == '/' ) break;
    if (filename[j] == '.' ) {
      index_p = j;
      break;
    }
  }
  if (index_p == -1 || index_p == 0){
    return -1;
  }

  char *b = new char[index_p+1];
  strncpy(b, filename, index_p);
  b[index_p] = '\0';
  *basename = b;
  return 0;
}

// test existence of files
static
int stat_file(const char* b){
  struct stat statbuf;
  if (0 != stat(b,&statbuf)){
    cerr << b << " is not readable." << endl;
    return -1;
  }
  if (! S_ISREG(statbuf.st_mode)){
    cerr << b << " is invalid." << endl;
    return -1;
  }
  return 0;
}

int testBasename(const char *basename){
  if (basename == NULL || 0 == strcmp(basename,"")) return -1;

  const size_t len_b = strlen(basename);
  char *b = new char[len_b+10];
  strcpy(b,basename);
  // test for .nodes

  assert(b[len_b] == '\0'); // paranoid !
  b[len_b] = '\0';
  strcat(b,".nodes");
  if (0 != stat_file(b))
    goto fail;
  b[len_b] = '\0';
  strcat(b,".tri");
  if (0 != stat_file(b))
    goto fail;
  b[len_b] = '\0';
  strcat(b,".z");
  if (0 != stat_file(b))
    goto fail;

  delete [] b;
  return 0;
 fail:
  delete [] b;
  return -1;
}

void ReadChild
(
 int nStep,
 int TypeVariable,
 cxPyramid    **Pyr2D,
 cxParameter  **currentTime
 ) {
#ifdef DEBUG1
  cout << "Entering main function" << endl;
#endif
  //-----------------------------------------------------------------
  // Extract File Name
  char *basename(0);
  {
    char const * const filename = GetFileName();
#ifdef DEBUG1
    cout << "FileName=" << filename << endl;
#endif
    if (0 != IsFileNameValid(filename))
      return;
    if (0 != myBasename(filename, &basename)){
      cerr << "Filename does not have a suffix." << endl;
      return;
    }
#ifdef DEBUG1
    cout << "BaseName=" << basename << endl;
#endif
    if (0 != testBasename(basename))
      return;
  }
  //-----------------------------------------------------------------
  ReadChildData ChildData;
  try {
    if (!ChildData.LoadData(basename, nStep, TypeVariable)) {
      cerr << "Time step \"" << nStep << "\" does not exist." << endl;
      delete [] basename;
      return;
    }
  } catch (const BadFile &ex) {
    cerr << "Error when reading file \"" << ex.filename()
	 << "\": " << ex.ExceptionName()
	 << "." << endl;
    delete [] basename;
    return;
  } catch (...) {
    cerr << "A unkown exception occured during file processing." << endl;
    delete [] basename;
    return;
  }
  delete [] basename; basename = 0;
  const size_t npoints = ChildData.nnodes();
  const size_t nelem = ChildData.ntri();
  assert( npoints > 0 );
  assert( nelem > 0 );

#ifdef DEBUG1
  cout << "Data loaded." << endl;
#endif
  // set time
  *currentTime = cxParamDoubleNew(ChildData.currentTime());
  //-----------------------------------------------------------------
  // Pyramid building
  cxLattice_var baselat;                // base lattice
  cxConnection_var conn;                // elt2node connectivity
  cxPyramid_var Pyr2Dt;
  FLOAT *latcoord  = 0;                 // lattice coordinate buffer
  FLOAT *latdata  = 0;                  // lattice data buffer
  long *elem_  = 0;
  long *connec  = 0;
  cxErrorCode ec = cx_err_none;

  long nbn = npoints;   // nb of nodes
  const long nbe = nelem;     // nb of elements
  const long nbnve = 3*nelem; // nb of vertices
                              // 3 nodes per triangles

#ifdef DEBUG1
  cerr << "Nodes "    << nbn   << endl
       << "Elements " << nbe   << endl
       << "Vertices " << nbnve << endl;
#endif
  //-----------------------------------------------------------------
  // Allocate Explorer Type

  // Allocate base lattice
  baselat= cxLatNew(1,            /* 1D lattice */
		    &nbn,         /* where dims[] is nbne */
		    1,            /* 1 variables / node */
		    CXFLOAT,      /* type is float */
		    2,            /* number of coordinates / node */
		    // 3 for x,y,z
		    cx_coord_curvilinear /* curvilinear coordinates */
		    );
  if (cxDataAllocErrorGet()){
    cxModAlert("Error. Memory allocation failed for base lattice.");
    cxDataAllocErrorClear();
    return;
  }
  // Allocate pyramid
  Pyr2Dt = cxPyrNew(0);
  if (cxDataAllocErrorGet()){
    cxModAlert("Error. Memory allocation failed for Pyramid.");
    cxDataAllocErrorClear();
    return;
  }
  // Allocate connectivity
  conn = cxConnNew(nbe,nbnve);
  if (cxDataAllocErrorGet()){
    cxModAlert("Error. Memory allocation failed for connectivity");
    cxDataAllocErrorClear();
    return;
  }
  // Allocate and set Pyramid Dictionary
  long *iptr  = 0;
  {
    cxPyramidDictionary_var dict;
    dict = cxPyrDictDefault( 2 );         // triangle/quadrangle dict.
    if ( !dict ) {
      cxModAlert("Error while allocating dictionnary");
      cxDataAllocErrorClear();
      return;
    }
    cxPyramidDictionarySet(Pyr2Dt, dict, &ec );
    if ( cx_err_none != ec ){
      cxModAlert("Error while setting dictionnary");
      cxDataAllocErrorClear();
      return;
    } else {
      dict._retn();
    }
  }
  cxPyramidCompressionTypeSet(Pyr2Dt,cx_compress_unique, &ec);
  if ( cx_err_none != ec ){
    cxModAlert("Error during cxPyramidCompressionTypeSet.");
    cxDataAllocErrorClear();
    return;
  }
  iptr = (long *)cxPyramidCompressionIndexGet(Pyr2Dt, &ec);
  if ( cx_err_none != ec ){
    cxModAlert("Error during cxPyramidCompressionIndexGet.");
    cxDataAllocErrorClear();
    return;
  }
  iptr[0] = cx_pyramid_dict_triangle;

    //-----------------------------------------------------------------
    // Build and set base Lattice
    /* Fetch pointers and fill it with coordinates and data */
  {
    void *_latdata, *_latcoord;
    ec=cxLatPtrGet(baselat,
		   NULL,
		   &_latdata,
		   NULL,
		   &_latcoord
		   );
    latdata = static_cast<FLOAT *>(_latdata);
    latcoord = static_cast<FLOAT *>(_latcoord);
  }
  if ( cx_err_none != ec){
    cxModAlert("Error. base lattice corrupted.");
    cxDataAllocErrorClear();
    return;
  }

  {
    for(int inode=0;inode<nbn;inode++){
      latcoord[2*inode  ] = ChildData.x[inode];
      latcoord[2*inode+1] = ChildData.y[inode];
    }
  }
  {
    // Data
    for(int inode=0;inode<nbn;inode++){
      latdata[inode] = ChildData.z[inode];
    }
  }

  ec = cxPyrSet(Pyr2Dt,baselat);   /* set base lattice */
  if ( cx_err_none != ec){
    cxModAlert("Error during set base lattice.");
    cxDataAllocErrorClear();
    return;
  } else {
    baselat._retn();
  }

  //-----------------------------------------------------------------
  // Set Pyramid Layer and set base Lattice by recovering data from CORBA object

  ec = cxPyrLayerSet(Pyr2Dt,1,NULL,NULL); /* nullify first connectivity level */
  if ( cx_err_none != ec){
    cxModAlert("Error during cxPyrLayerSet.");
    cxDataAllocErrorClear();
    return;
  }

  /* Fetch pointers and set up the connections list */
  ec = cxConnPtrGet(conn,NULL,NULL,&elem_,&connec);
  if ( cx_err_none != ec){
    cxModAlert("Error during cxConnPtrGet.");
    cxDataAllocErrorClear();
    return;
  }
  {
    // element to vertex connectivity table
    for(int ielem=0;ielem<nbe;ielem++){
      connec[3*ielem  ]= ChildData.p0[ielem];
      connec[3*ielem+1]= ChildData.p1[ielem];
      connec[3*ielem+2]= ChildData.p2[ielem];
    }
  }
  // build element to node table
  for(int ielem=0;ielem<(nbe+1);ielem++){
    elem_[ielem]= ielem * 3;  /* 3 nodes per elements */
  }

  ec = cxPyrLayerSet(Pyr2Dt,2,conn,NULL);
  if ( cx_err_none != ec){
    cxModAlert("Error during cxPyrLayerSet.");
    cxDataAllocErrorClear();
    return;
  } else {
    conn._retn();
  }

  //-----------------------------------------------------------------
  // Return the pyramid
  *Pyr2D = Pyr2Dt._retn();

  return;
}
<|endoftext|>


<commit_before>#ifndef _STEAMVDFPARSE_H_
#define _STEAMVDFPARSE_H_

#include <boost/property_tree/ptree.hpp>

#include <cstdint>
#include <fstream>
#include <iostream>
#include <unordered_map>

#define MAGIC_VALUE 0x07564426

/** Steam VDF Parsing.
 * A bunch of utility functions to parse the Steam VDF binary format
 */
namespace SteamVdfParse
{

namespace pt = boost::property_tree;

/** Function to convert an istream object into a 32-bit little endian integer.
 * \param stream The stream to convert
 * \return The converted integer
 */
inline uint32_t read32_le(std::istream& stream)
{
    return static_cast<uint32_t>((stream.get()) | (stream.get() << 8) | (stream.get() << 16) |
                                 (stream.get() << 24));
}

/** Function to convert an istream object into a 64-bit little endian integer.
 * \param stream The stream to convert
 * \return The converted integer
 */
inline uint64_t read64_le(std::istream& stream)
{
    return static_cast<uint64_t>(
        (stream.get()) | (stream.get() << 8) | (stream.get() << 16) | (stream.get() << 24) |
        ((uint64_t)stream.get() << 32) | ((uint64_t)stream.get() << 40) |
        ((uint64_t)stream.get() << 48) | ((uint64_t)stream.get() << 56));
}

/** Function to convert an istream object into a std::string.
 * \param stream The stream to convert
 * \return The converted string
 */
inline std::string readString(std::istream& stream)
{
    std::string str;
    std::getline(stream, str, '\0');
    return str;
}

/** Struct containing information about a game, as well as a property tree of
 * the parsed sections.
 */
struct GameHeader
{
    uint32_t appID; /**< Steam ID of the game */
    uint32_t size; /**< Size on disk */
    uint32_t infoState;  /**< State of the game, 1-unavailable, 2-available */
    uint32_t lastUpdated; /**< UNIX time of the last update */
    uint64_t accessToken; /**< Token needed to auth services (if needed) */
    uint8_t sha[20]; /**< Checksum of the fs */
    uint32_t changeNumber; /**< ID of the latest change on the game repo */
    pt::ptree pt; /**< Unordered sections of the games in appinfo */
};

/** Take an istream object and a flag to check if the current node is the root
 * node, as well as the key name, and translate the bytes into a property tree.
 * \param input The stream to translate
 * \param root A flag to check if the current node is root
 * \param name Name of the key to use in the section
 * \return The parsed property tree
 * \sa parseGame(), parseVdf()
 */
inline pt::ptree parseSection(std::istream& input, bool root, std::string name)
{
    pt::ptree section;

    while (true)
    {
        uint8_t valueType = input.get();

        if (valueType == 0x08)
        {
            if (root)
            {
                input.get();
            }
            break;
        }

        std::string key = readString(input);

        switch (valueType)
        {
            case 0x00:  // None
            {
                section.add_child(key, parseSection(input, false, key));
                break;
            }
            case 0x01:  // string
            {
                section.put(key, readString(input));
                break;
            }
            case 0x02:  // int
            {
                section.put(key, read32_le(input));
                break;
            }
            case 0x03:  // float
            {
                std::cerr << "Floats are not implemented." << std::endl;
                break;
            }
            case 0x04:  // ptr
            {
                std::cerr << "Pointers are not implemented." << std::endl;
                break;
            }
            case 0x05:  // Wide string
            {
                std::cerr << "Wide strings are not implemented." << std::endl;
                break;
            }
            case 0x06:  // Colour
            {
                std::cerr << "Colours are not implemented." << std::endl;
                break;
            }
            case 0x07:  // 64 bit int
            {
                section.put(key, read64_le(input));
                break;
            }
            default:
                std::cerr << "Unknown type: " << (int)valueType << std::endl;
        }
    }

    return section;
}

/** Take an istream object, file expected, and convert the block of bytes to a
 * GameHeader type.
 * \param input The stream to translate
 * \return A GameHeader of the section
 * \sa parseSection(), parseVdf()
 */
inline GameHeader parseGame(std::istream& input)
{
    GameHeader game;
    game.appID = read32_le(input);
    if (game.appID == 0)
    {
        return game;
    }

    game.size = read32_le(input);
    game.infoState = read32_le(input);
    game.lastUpdated = read32_le(input);
    game.accessToken = read64_le(input);

    for (int i = 0; i < 20; i++)
    {
        game.sha[i] = input.get();
    }

    game.changeNumber = read32_le(input);

    while (true)
    {
        uint8_t sectionID = input.get();
        if (sectionID == 0x00)
        {
            break;
        }

        input.get();  // read the 00 before name

        std::string name = readString(input);
        pt::ptree section = parseSection(input, true, name);
        game.pt.add_child(name, section);
    }

    return game;
}

/** Takes the location of an appinfo file and handles the parsing if the file is
 * correct.
 * \param location Location of the appinfo file
 * \return A full map of each game, with the key being the game's Steam ID
 * \sa parseSection(), parseVdf()
 */
inline std::unordered_map<int, GameHeader> parseVdf(std::string location)
{
    std::ifstream input(location, std::ifstream::binary);

    uint32_t magic = read32_le(input);
    uint32_t universe = read32_le(input);  // Parse this later

    std::unordered_map<int, GameHeader> games;

    if (magic != MAGIC_VALUE)
    {
        std::cerr << "Invalid magic value!" << std::endl;
        return games;
    }

    while (!input.eof())
    {
        GameHeader game = parseGame(input);
        if (game.appID == 0)
        {
            break;
        }
        games.insert(std::make_pair(game.appID, game));
    }

    return games;
}
}

#endif
<commit_msg>Remove uneeded "library"<commit_after><|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <globals.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream.h>
#include "Instrument.h"
#include "rt.h"
#include "rtdefs.h"
#include <notetags.h>
#include <sndlibsupport.h>
#include <bus.h>
#include <assert.h>

/* ----------------------------------------------------------- Instrument --- */
Instrument :: Instrument()
{
   start = 0.0;
   dur = 0.0;
   cursamp = 0;
   chunksamps = 0;
   endsamp = 0;
   nsamps = 0;
   chunkstart = 0;
   output_offset = 0;

   sfile_on = 0;                // default is no input soundfile
   fdIndex = NO_DEVICE_FDINDEX;
   fileOffset = 0;

   inputsr = 0.0;
   inputchans = 0;
   outputchans = 0;

// FIXME: not clear we need inbuf - better to leave it on run method's stack?
   inbuf = NULL;
   outbuf = NULL;

   bus_config = NULL;

   if (tags_on) {
      pthread_mutex_lock(&pfieldLock);

      for (int i = 0; i < MAXPUPS; i++)  // initialize this element
         pupdatevals[curtag][i] = NOPUPDATE;
      mytag = curtag++;

      if (curtag >= MAXPUPARR)
         curtag = 1;            // wrap it around
      // 0 is reserved for all-note rtupdates

      pthread_mutex_unlock(&pfieldLock);
   }
}

/* ---------------------------------------------------------- ~Instrument --- */
Instrument :: ~Instrument()
{
   if (sfile_on)
      gone();                   // decrement input soundfile reference

   delete [] inbuf;
   delete [] outbuf;

// FIXME: Also...
// Call something that decrements refcount for bus_config, and if that
// reaches zero, and is no longer the most recent for that instname,
// then delete that bus_config node.
}

/* ------------------------------------------------------- set_bus_config --- */
/* Set the bus_config pointer to the right bus_config for this inst.
   Then set the inputchans and outputchans members accordingly.

   Instruments *must* call this from within their makeINSTNAME method. E.g.,

       WAVETABLE *inst = new WAVETABLE();
       inst->set_bus_config("WAVETABLE");
*/
void Instrument :: set_bus_config(const char *inst_name)
{
   bus_config = get_bus_config(inst_name);

   inputchans = bus_config->in_count + bus_config->auxin_count;
   outputchans = bus_config->out_count + bus_config->auxout_count;
}

/* ----------------------------------------------------------------- init --- */
int Instrument :: init(float p[], short n_args)
{
   cout << "You haven't defined an init member of your Instrument class!"
                                                                   << endl;
   return -1;
}

/* ------------------------------------------------------------------ run --- */
/* Instruments *must* call this at the beginning of their run methods,
   like this:

      Instrument::run();

   This method allocates the instrument's private interleaved output buffer
   and inits a buffer status array.
   Note: We allocate here, rather than in ctor or init method, because this
   will mean less memory overhead before the inst begins playing.
*/
int Instrument :: run()
{
   if (outbuf == NULL)
      outbuf = new BUFTYPE [RTBUFSAMPS * outputchans];

   obufptr = outbuf;

#ifdef NOTYET
   for (int i = 0; i < outputchans; i++)
      bufstatus[i] = 0;
#endif

   return 0;
}

/* ----------------------------------------------------------------- exec --- */
void Instrument :: exec()
{
   run();
}

/* ------------------------------------------------------------- rtaddout --- */
/* Replacement for the old rtaddout (in rtaddout.C, now removed).
   This one copies (not adds) into the inst's outbuf. Later the
   scheduler calls the insts addout method to add outbuf into the
   appropriate output buses. Inst's *must* call the class run method
   before doing their own run stuff. (This is true even if they don't
   use rtaddout.)
   Assumes that <samps> contains exactly outputchans interleaved samples.
   Returns outputchans (i.e., number of samples written).
*/
int Instrument :: rtaddout(BUFTYPE samps[])
{
   for (int i = 0; i < outputchans; i++)
      *obufptr++ = samps[i];

   return outputchans;
}

/* --------------------------------------------------------------- addout --- */
/* Add signal from one channel of instrument's private interleaved buffer
   into the specified output bus.
*/
void Instrument :: addout(BusType bus_type, int bus)
{
   int      samp_index, endframe, src_chan, buses;
   short    *bus_list;
   BufPtr   src, dest;

   assert(bus >= 0 && bus < MAXBUS);

   if (bus_type == BUS_AUX_OUT) {
      dest = aux_buffer[bus];
      buses = bus_config->auxout_count;
      bus_list = bus_config->auxout;
   }
   else {       /* BUS_OUT */
      dest = out_buffer[bus];
      buses = bus_config->out_count;
      bus_list = bus_config->out;
   }

   src_chan = -1;
   for (int i = 0; i < buses; i++) {
      if (bus_list[i] == bus) {
         src_chan = i;
         break;
      }
   }

   assert(src_chan != -1);
   assert(dest != NULL);

   endframe = output_offset + chunksamps;
   samp_index = src_chan;

// FIXME: pthread_mutex_lock dest buffer

   for (int frame = output_offset; frame < endframe; frame++) {
      dest[frame] += outbuf[samp_index];
      samp_index += outputchans;
   }

// FIXME: pthread_mutex_unlock dest buffer
}

/* ------------------------------------------------------------- getstart --- */
float Instrument :: getstart()
{
   return start;
}

/* --------------------------------------------------------------- getdur --- */
float Instrument :: getdur()
{
   return dur;
}

/* ----------------------------------------------------------- getendsamp --- */
int Instrument :: getendsamp()
{
   return endsamp;
}

/* ----------------------------------------------------------- setendsamp --- */
void Instrument :: setendsamp(int end)
{
   endsamp = end;
}

/* ------------------------------------------------------------- setchunk --- */
void Instrument :: setchunk(int csamps)
{
   chunksamps = csamps;
}

/* -------------------------------------------------------- setchunkstart --- */
void Instrument :: setchunkstart(int csamps)
{
   chunkstart = csamps;
}

/* ---------------------------------------------------- set_output_offset --- */
void Instrument :: set_output_offset(int offset)
{
   output_offset = offset;
}

/* ----------------------------------------------------------------- gone --- */
/* If the reference count on the file referenced by the instrument
   reaches zero, close the input soundfile and set the state to
   make sure this is obvious.
*/
void Instrument :: gone()
{
#ifdef DEBUG
   printf("Instrument::gone(this=0x%x): index %d refcount = %d\n",
          this, fdIndex, inputFileTable[fdIndex].refcount);
#endif

   // BGG -- added this to prevent file closings in interactive mode
   // we don't know if a file will be referenced again in the future
   if (!rtInteractive) {
      if (fdIndex >= 0 && --inputFileTable[fdIndex].refcount <= 0) {
         if (inputFileTable[fdIndex].fd > 0) {
#ifdef DEBUG
            printf("\tclosing fd %d\n", inputFileTable[fdIndex].fd);
#endif
            clm_close(inputFileTable[fdIndex].fd);
         }
         if (inputFileTable[fdIndex].filename);
            free(inputFileTable[fdIndex].filename);
         inputFileTable[fdIndex].filename = NULL;
         inputFileTable[fdIndex].fd = NO_FD;
         inputFileTable[fdIndex].header_type = unsupported_sound_file;
         inputFileTable[fdIndex].data_format = snd_unsupported;
         inputFileTable[fdIndex].data_location = 0;
         inputFileTable[fdIndex].srate = 0.0;
         inputFileTable[fdIndex].chans = 0;
         inputFileTable[fdIndex].dur = 0.0;
         fdIndex = -1;
      }
   }
}

<commit_msg>Try to make exec know whether it should call addout. Involves keeping track of things using the needs_to_run flag and the bufstatus flag array.<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <globals.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream.h>
#include "Instrument.h"
#include "rt.h"
#include "rtdefs.h"
#include <notetags.h>
#include <sndlibsupport.h>
#include <bus.h>
#include <assert.h>

/* ----------------------------------------------------------- Instrument --- */
Instrument :: Instrument()
{
   start = 0.0;
   dur = 0.0;
   cursamp = 0;
   chunksamps = 0;
   endsamp = 0;
   nsamps = 0;
   chunkstart = 0;
   output_offset = 0;

   sfile_on = 0;                // default is no input soundfile
   fdIndex = NO_DEVICE_FDINDEX;
   fileOffset = 0;

   inputsr = 0.0;
   inputchans = 0;
   outputchans = 0;

// FIXME: not clear we need inbuf - better to leave it on run method's stack?
   inbuf = NULL;
   outbuf = NULL;

   bus_config = NULL;

   for (int i = 0; i < MAXBUS; i++)
      bufstatus[i] = 0;
   needs_to_run = 1;

   if (tags_on) {
      pthread_mutex_lock(&pfieldLock);

      for (int i = 0; i < MAXPUPS; i++)  // initialize this element
         pupdatevals[curtag][i] = NOPUPDATE;
      mytag = curtag++;

      if (curtag >= MAXPUPARR)
         curtag = 1;            // wrap it around
      // 0 is reserved for all-note rtupdates

      pthread_mutex_unlock(&pfieldLock);
   }
}

/* ---------------------------------------------------------- ~Instrument --- */
Instrument :: ~Instrument()
{
   if (sfile_on)
      gone();                   // decrement input soundfile reference

   delete [] inbuf;
   delete [] outbuf;

// FIXME: Also...
// Call something that decrements refcount for bus_config, and if that
// reaches zero, and is no longer the most recent for that instname,
// then delete that bus_config node.
}

/* ------------------------------------------------------- set_bus_config --- */
/* Set the bus_config pointer to the right bus_config for this inst.
   Then set the inputchans and outputchans members accordingly.

   Instruments *must* call this from within their makeINSTNAME method. E.g.,

       WAVETABLE *inst = new WAVETABLE();
       inst->set_bus_config("WAVETABLE");
*/
void Instrument :: set_bus_config(const char *inst_name)
{
   bus_config = get_bus_config(inst_name);

   inputchans = bus_config->in_count + bus_config->auxin_count;
   outputchans = bus_config->out_count + bus_config->auxout_count;
}

/* ----------------------------------------------------------------- init --- */
int Instrument :: init(float p[], short n_args)
{
   cout << "You haven't defined an init member of your Instrument class!"
                                                                   << endl;
   return -1;
}

/* ------------------------------------------------------------------ run --- */
/* Instruments *must* call this at the beginning of their run methods,
   like this:

      Instrument::run();

   This method allocates the instrument's private interleaved output buffer
   and inits a buffer status array.
   Note: We allocate here, rather than in ctor or init method, because this
   will mean less memory overhead before the inst begins playing.
*/
int Instrument :: run()
{
   if (outbuf == NULL)
      outbuf = new BUFTYPE [RTBUFSAMPS * outputchans];

   obufptr = outbuf;

   for (int i = 0; i < outputchans; i++)
      bufstatus[i] = 0;

   needs_to_run = 0;

   return 0;
}

/* ----------------------------------------------------------------- exec --- */
/* Called from inTraverse to do one or both of these tasks:

      1) run the instrument for the current timeslice, and/or

      2) call addout to transfer a channel from the private instrument
         output buffer to one of the global output buffers.

   exec(), run() and addout() work together to decide whether a given
   call to exec needs to run or addout. The first call to exec for a
   given timeslice does both; subsequent calls during the same timeslice
   only addout.
*/
void Instrument :: exec(BusType bus_type, int bus)
{
   int done;

   if (needs_to_run)
      run();

   addout(bus_type, bus);

   /* Decide whether we'll call run() next time. */
   done = 1;
   for (int i = 0; i < outputchans; i++) {
      if (bufstatus[i] == 0) {
         done = 0;
         break;
      }
   }
   if (done)
      needs_to_run = 1;
}

/* ------------------------------------------------------------- rtaddout --- */
/* Replacement for the old rtaddout (in rtaddout.C, now removed).
   This one copies (not adds) into the inst's outbuf. Later the
   scheduler calls the insts addout method to add outbuf into the
   appropriate output buses. Inst's *must* call the class run method
   before doing their own run stuff. (This is true even if they don't
   use rtaddout.)
   Assumes that <samps> contains exactly outputchans interleaved samples.
   Returns outputchans (i.e., number of samples written).
*/
int Instrument :: rtaddout(BUFTYPE samps[])
{
   for (int i = 0; i < outputchans; i++)
      *obufptr++ = samps[i];

   return outputchans;
}

/* --------------------------------------------------------------- addout --- */
/* Add signal from one channel of instrument's private interleaved buffer
   into the specified output bus.
*/
void Instrument :: addout(BusType bus_type, int bus)
{
   int      samp_index, endframe, src_chan, buses;
   short    *bus_list;
   BufPtr   src, dest;

   assert(bus >= 0 && bus < MAXBUS);

   if (bus_type == BUS_AUX_OUT) {
      dest = aux_buffer[bus];
      buses = bus_config->auxout_count;
      bus_list = bus_config->auxout;
   }
   else {       /* BUS_OUT */
      dest = out_buffer[bus];
      buses = bus_config->out_count;
      bus_list = bus_config->out;
   }

   src_chan = -1;
   for (int i = 0; i < buses; i++) {
      if (bus_list[i] == bus) {
         src_chan = i;
         break;
      }
   }

   assert(src_chan != -1);
   assert(dest != NULL);

   endframe = output_offset + chunksamps;
   samp_index = src_chan;

// FIXME: pthread_mutex_lock dest buffer

   for (int frame = output_offset; frame < endframe; frame++) {
      dest[frame] += outbuf[samp_index];
      samp_index += outputchans;
   }

// FIXME: pthread_mutex_unlock dest buffer

   /* Show exec() that we've written this chan. */
   bufstatus[src_chan] = 1;
}

/* ------------------------------------------------------------- getstart --- */
float Instrument :: getstart()
{
   return start;
}

/* --------------------------------------------------------------- getdur --- */
float Instrument :: getdur()
{
   return dur;
}

/* ----------------------------------------------------------- getendsamp --- */
int Instrument :: getendsamp()
{
   return endsamp;
}

/* ----------------------------------------------------------- setendsamp --- */
void Instrument :: setendsamp(int end)
{
   endsamp = end;
}

/* ------------------------------------------------------------- setchunk --- */
void Instrument :: setchunk(int csamps)
{
   chunksamps = csamps;
}

/* -------------------------------------------------------- setchunkstart --- */
void Instrument :: setchunkstart(int csamps)
{
   chunkstart = csamps;
}

/* ---------------------------------------------------- set_output_offset --- */
void Instrument :: set_output_offset(int offset)
{
   output_offset = offset;
}

/* ----------------------------------------------------------------- gone --- */
/* If the reference count on the file referenced by the instrument
   reaches zero, close the input soundfile and set the state to
   make sure this is obvious.
*/
void Instrument :: gone()
{
#ifdef DEBUG
   printf("Instrument::gone(this=0x%x): index %d refcount = %d\n",
          this, fdIndex, inputFileTable[fdIndex].refcount);
#endif

   // BGG -- added this to prevent file closings in interactive mode
   // we don't know if a file will be referenced again in the future
   if (!rtInteractive) {
      if (fdIndex >= 0 && --inputFileTable[fdIndex].refcount <= 0) {
         if (inputFileTable[fdIndex].fd > 0) {
#ifdef DEBUG
            printf("\tclosing fd %d\n", inputFileTable[fdIndex].fd);
#endif
            clm_close(inputFileTable[fdIndex].fd);
         }
         if (inputFileTable[fdIndex].filename);
            free(inputFileTable[fdIndex].filename);
         inputFileTable[fdIndex].filename = NULL;
         inputFileTable[fdIndex].fd = NO_FD;
         inputFileTable[fdIndex].header_type = unsupported_sound_file;
         inputFileTable[fdIndex].data_format = snd_unsupported;
         inputFileTable[fdIndex].data_location = 0;
         inputFileTable[fdIndex].srate = 0.0;
         inputFileTable[fdIndex].chans = 0;
         inputFileTable[fdIndex].dur = 0.0;
         fdIndex = -1;
      }
   }
}

<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <globals.h>
#include <pthread.h>
#include "../rtstuff/Instrument.h"
#include "../rtstuff/rt.h"
#include "../rtstuff/rtdefs.h"
#include "../sys/mixerr.h"
#include <string.h>
#include <iostream.h>
#include "defs.h"

extern void heapSched(Instrument *Iptr);

extern "C" {
double checkInsts(char *fname, double *pp, short n_args)
{
	int i;
	rt_item *rt_p;
	rt_item *rt_temp;
	Instrument *Iptr;
	double rv;
	float p[MAXDISPARGS];

	/* printf("ENTERING checkInsts() FUNCTION -----\n"); */

	/* convert pp to floats */
	for(i = 0; i < n_args; i++) p[i] = (float)pp[i];
	/* and zero out the rest */
	for(i = n_args; i < MAXDISPARGS; i++) p[i] = pp[i] = 0.0;

	mixerr = MX_FNAME;
	rt_temp = rt_list;
	rt_p = rt_list;

	while (rt_p) {

		if((rv=strcmp(rt_p->rt_name,fname)) == 0) {
			if(print_is_on) {
				printf ("========<rt-queueing>=======\n");
				printf ("%s:  ",fname);
				for (i = 0; i < n_args; i++)  printf ("%f ",p[i]);
				printf("\n");
			}

			/* set up the Instrument */

			Iptr = (*(rt_p->rt_ptr))();

			Iptr->init(p,n_args);

			/* schedule instrument */

			pthread_mutex_lock(&heapLock);
			heapSched(Iptr);
			pthread_mutex_unlock(&heapLock);

			rv = 1;
			mixerr = MX_NOERR;
			rt_list = rt_temp;

			/* printf("EXITING checkInsts() FUNCTION -----\n"); */
			return rv;
		}
		rt_p = rt_p->rt_next;
	}
	rt_list = rt_temp;
	/* printf("EXITING checkInsts() FUNCTION (function not found) -----\n"); */
	return 0; /* This was NULL on SGI's ... not good */
}
}

<commit_msg>Update inclusion scheme.<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <globals.h>
#include <prototypes.h>
#include <maxdispargs.h>
#include <pthread.h>
#include "../rtstuff/Instrument.h"
#include "../rtstuff/rt.h"
#include "../rtstuff/rtdefs.h"
#include "../sys/mixerr.h"
#include <stdio.h>
#include <string.h>

extern void heapSched(Instrument *Iptr);

extern "C" {
double checkInsts(char *fname, double *pp, short n_args)
{
	int i;
	rt_item *rt_p;
	rt_item *rt_temp;
	Instrument *Iptr;
	double rv;
	float p[MAXDISPARGS];

	/* printf("ENTERING checkInsts() FUNCTION -----\n"); */

	/* convert pp to floats */
	for(i = 0; i < n_args; i++) p[i] = (float)pp[i];
	/* and zero out the rest */
	for(i = n_args; i < MAXDISPARGS; i++) p[i] = pp[i] = 0.0;

	mixerr = MX_FNAME;
	rt_temp = rt_list;
	rt_p = rt_list;

	while (rt_p) {

		if((rv=strcmp(rt_p->rt_name,fname)) == 0) {
			if(print_is_on) {
				printf ("========<rt-queueing>=======\n");
				printf ("%s:  ",fname);
				for (i = 0; i < n_args; i++)  printf ("%f ",p[i]);
				printf("\n");
			}

			/* set up the Instrument */

			Iptr = (*(rt_p->rt_ptr))();

			Iptr->init(p,n_args);

			/* schedule instrument */

			pthread_mutex_lock(&heapLock);
			heapSched(Iptr);
			pthread_mutex_unlock(&heapLock);

			rv = 1;
			mixerr = MX_NOERR;
			rt_list = rt_temp;

			/* printf("EXITING checkInsts() FUNCTION -----\n"); */
			return rv;
		}
		rt_p = rt_p->rt_next;
	}
	rt_list = rt_temp;
	/* printf("EXITING checkInsts() FUNCTION (function not found) -----\n"); */
	return 0; /* This was NULL on SGI's ... not good */
}
}

<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/

/* rev for v2.3 by JGG */

#include <globals.h>
#include <stdio.h>
#include <assert.h>
#include "../rtstuff/Instrument.h"
#include "../rtstuff/rtdefs.h"

extern "C" {
extern int get_last_input_index(void);       /* defined in rtinput.c */
}

#define INCHANS_DISCREPANCY_WARNING "\
WARNING: The bus config for this instrument specifies %d input channels, \n\
but its input source has %d channels.\n"

/* ----------------------------------------------------------- rtsetinput --- */
/* Instruments call this to set their input file pointer (like setnote in cmix).
   Returns 0 if ok, -1 if error.
*/
int
rtsetinput(float start_time, Instrument *inst)
{
   int auxin_count = inst->bus_config->auxin_count;
   int in_count = inst->bus_config->in_count;

   if (auxin_count == 0 && in_count == 0) {
      fprintf(stderr, "This instrument requires input from either an in bus"
                      "or an aux bus.\n Change this with bus_config().\n");
      exit(1);
   }

   if (auxin_count > 0) {
      if (start_time != 0.0) {
         fprintf(stderr, "inskip must be 0 when reading from an aux bus.\n");
         exit(1);
      }
   }

   if (in_count > 0) {
      int src_chans;
      int index = get_last_input_index();

      if (index < 0 || inputFileTable[index].fd < 1) {
         fprintf(stderr, "No input source open for this instrument!\n");
         return -1;
      }

      /* File or audio device was opened in rtinput(). Here we store the
         index into the inputFileTable for the file or device.
      */
      inst->fdIndex = index;

      /* Fill in relevant data members of instrument class. */
      inst->inputsr = inputFileTable[index].srate;

      src_chans = inputFileTable[index].chans;

      if (inst->inputchans != src_chans) {
         fprintf(stderr, INCHANS_DISCREPANCY_WARNING, inst->inputchans,
                                                                  src_chans);
      }

      if (inputFileTable[index].is_audio_dev) {
         if (start_time != 0.0) {
            fprintf(stderr, "inskip must be 0 when reading from the real-time "
                            "audio device.\n");
            exit(1);
         }
      }
      else {
         int datum_size, inskip;

         inst->sfile_on = 1;

         inskip = (int) (start_time * inst->inputsr);

         /* sndlib always uses 2 for datum size, even if the actual size is
            different. However, we don't use sndlib to read float files, so
            their datum size is the real thing.
         */
         if (inputFileTable[index].is_float_format)
            datum_size = sizeof(float);
         else
            datum_size = 2;

         /* Offset is measured from the header size determined in rtinput(). */
         inst->fileOffset = inputFileTable[index].data_location
                            + (inskip * inst->inputchans * datum_size);

         if (start_time >= inputFileTable[index].dur)
            fprintf(stderr, "WARNING: Attempt to read past end of input "
                            "file: %s\n", inputFileTable[index].filename);
      }

      /* Increment the reference count for this file. */
      inputFileTable[index].refcount++;
   }

   return 0;
}

<commit_msg>Err msg typo.<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/

/* rev for v2.3 by JGG */

#include <globals.h>
#include <stdio.h>
#include <assert.h>
#include "../rtstuff/Instrument.h"
#include "../rtstuff/rtdefs.h"

extern "C" {
extern int get_last_input_index(void);       /* defined in rtinput.c */
}

#define INCHANS_DISCREPANCY_WARNING "\
WARNING: The bus config for this instrument specifies %d input channels, \n\
but its input source has %d channels.\n"

/* ----------------------------------------------------------- rtsetinput --- */
/* Instruments call this to set their input file pointer (like setnote in cmix).
   Returns 0 if ok, -1 if error.
*/
int
rtsetinput(float start_time, Instrument *inst)
{
   int auxin_count = inst->bus_config->auxin_count;
   int in_count = inst->bus_config->in_count;

   if (auxin_count == 0 && in_count == 0) {
      fprintf(stderr, "This instrument requires input from either an in bus "
                      "or an aux bus.\n Change this with bus_config().\n");
      exit(1);
   }

   if (auxin_count > 0) {
      if (start_time != 0.0) {
         fprintf(stderr, "inskip must be 0 when reading from an aux bus.\n");
         exit(1);
      }
   }

   if (in_count > 0) {
      int src_chans;
      int index = get_last_input_index();

      if (index < 0 || inputFileTable[index].fd < 1) {
         fprintf(stderr, "No input source open for this instrument!\n");
         return -1;
      }

      /* File or audio device was opened in rtinput(). Here we store the
         index into the inputFileTable for the file or device.
      */
      inst->fdIndex = index;

      /* Fill in relevant data members of instrument class. */
      inst->inputsr = inputFileTable[index].srate;

      src_chans = inputFileTable[index].chans;

      if (inst->inputchans != src_chans) {
         fprintf(stderr, INCHANS_DISCREPANCY_WARNING, inst->inputchans,
                                                                  src_chans);
      }

      if (inputFileTable[index].is_audio_dev) {
         if (start_time != 0.0) {
            fprintf(stderr, "inskip must be 0 when reading from the real-time "
                            "audio device.\n");
            exit(1);
         }
      }
      else {
         int datum_size, inskip;

         inst->sfile_on = 1;

         inskip = (int) (start_time * inst->inputsr);

         /* sndlib always uses 2 for datum size, even if the actual size is
            different. However, we don't use sndlib to read float files, so
            their datum size is the real thing.
         */
         if (inputFileTable[index].is_float_format)
            datum_size = sizeof(float);
         else
            datum_size = 2;

         /* Offset is measured from the header size determined in rtinput(). */
         inst->fileOffset = inputFileTable[index].data_location
                            + (inskip * inst->inputchans * datum_size);

         if (start_time >= inputFileTable[index].dur)
            fprintf(stderr, "WARNING: Attempt to read past end of input "
                            "file: %s\n", inputFileTable[index].filename);
      }

      /* Increment the reference count for this file. */
      inputFileTable[index].refcount++;
   }

   return 0;
}

<|endoftext|>


<commit_before>#include <QtCore/QFile>
#include <QtCore/QDebug>

#include "dispatcherGenerator.h"
#include "nameNormalizer.h"

using namespace ubiq::generator;
using namespace qReal;

DispatcherGenerator::DispatcherGenerator(QString const &templateDirPath
		, QString const &outputDirPath
		, qReal::LogicalModelAssistInterface const &logicalModel
		, qReal::ErrorReporterInterface &errorReporter
		)
		: AbstractGenerator(templateDirPath , outputDirPath, logicalModel, errorReporter)
{
}

DispatcherGenerator::~DispatcherGenerator()
{
}

void DispatcherGenerator::generate()
{
	loadUtilsTemplates();

	foreach (Id const diagram, mApi.elementsByType("MasterNode")) { // get master node
		if (!mApi.isLogicalElement(diagram))
			continue;

		QString const templateName = "DeviceDispatcher.cs";

		QString fileTemplate;
		loadTemplateFromFile(templateName, fileTemplate);

		QString eventHadlers = generateEventHandlers(diagram);

		fileTemplate.replace("@@EventHandlers@@", eventHadlers);

		saveOutputFile(templateName, fileTemplate);
	}
}

QString DispatcherGenerator::generateEventHandlers(Id const &diagram)
{
	QString eventHadlers;
	foreach (Id const element, mApi.children(diagram)) { // get elements on master node
		if (!mApi.isLogicalElement(element) || (element.element() != "Handler"))
			continue;

		eventHadlers += generateEventHandler(mApi.name(element)); // generate code for each event handler
	}
	return eventHadlers;
}

QString DispatcherGenerator::generateConstants(qReal::Id const &element) const
{
	QString result;
	foreach (Id const id, mApi.children(element)) {
		if (!mApi.isLogicalElement(id) || id.element() != "MasterDiagramConstant")
			continue;

		QString constantTemplate = mTemplateUtils["@@MasterDiagramConstant@@"];
		QString const name = mApi.name(id);
		QString const type = mApi.stringProperty(id, "type");
		QString const value = mApi.stringProperty(id, "value");
		constantTemplate.replace("@@Name@@", NameNormalizer::normalize(name))
				.replace("@@Type@@", type)
				.replace("@@Value@@", value)
				;

		result += constantTemplate;
	}
	return result;
}

QString DispatcherGenerator::generateFields(qReal::Id const &element) const
{
	QString result;
	foreach (Id const id, mApi.children(element)) {
		if (!mApi.isLogicalElement(id) || id.element() != "MasterDiagramField")
			continue;

		QString constantTemplate = mTemplateUtils["@@MasterDiagramField@@"];
		QString const name = mApi.name(id);
		QString const type = mApi.stringProperty(id, "type");
		QString const value = mApi.stringProperty(id, "value");
		constantTemplate.replace("@@Name@@", NameNormalizer::normalize(name))
				.replace("@@Type@@", type)
				.replace("@@Value@@", value)
				;

		result += constantTemplate;
	}
	return result;
}

QString DispatcherGenerator::generateEventHandler(QString const handlerName)
{
	QString handlerCode = mTemplateUtils["@@EventHandler@@"];
	handlerCode.replace("@@HandlerName@@", handlerName);

	foreach (Id const diagram, mApi.elementsByType("UbiqActivityDiagram")) {
		// search for the diagram with name handlerName
		if (!mApi.isLogicalElement(diagram) || (mApi.name(diagram) != handlerName))
			continue;

		// diagram found, now get HandlerStart-s and generate cases

		QString cases;
		foreach (Id const &element, mApi.children(diagram)) {
			if (!mApi.isLogicalElement(diagram) || (element.element() != "HandlerStart"))
				continue;

			QString caseCode = mTemplateUtils["@@SwitchCase@@"];
			caseCode.replace("@@CaseValue@@", mApi.name(element));

			cases += caseCode;
		}
		handlerCode.replace("@@SwitchCases@@", cases);
	}

	return handlerCode;
}
<commit_msg>generation of constants and fields for dispatcher<commit_after>#include <QtCore/QFile>
#include <QtCore/QDebug>

#include "dispatcherGenerator.h"
#include "nameNormalizer.h"

using namespace ubiq::generator;
using namespace qReal;

DispatcherGenerator::DispatcherGenerator(QString const &templateDirPath
		, QString const &outputDirPath
		, qReal::LogicalModelAssistInterface const &logicalModel
		, qReal::ErrorReporterInterface &errorReporter
		)
		: AbstractGenerator(templateDirPath , outputDirPath, logicalModel, errorReporter)
{
}

DispatcherGenerator::~DispatcherGenerator()
{
}

void DispatcherGenerator::generate()
{
	loadUtilsTemplates();

	foreach (Id const diagram, mApi.elementsByType("MasterNode")) { // get master node
		if (!mApi.isLogicalElement(diagram))
			continue;

		QString const templateName = "DeviceDispatcher.cs";

		QString fileTemplate;
		loadTemplateFromFile(templateName, fileTemplate);

		QString eventHadlers = generateEventHandlers(diagram);

		fileTemplate.replace("@@EventHandlers@@", eventHadlers)
				.replace("@@Constants@@", generateConstants(diagram))
				.replace("@@Fields@@", generateFields(diagram))
				;

		saveOutputFile(templateName, fileTemplate);
	}
}

QString DispatcherGenerator::generateEventHandlers(Id const &diagram)
{
	QString eventHadlers;
	foreach (Id const element, mApi.children(diagram)) { // get elements on master node
		if (!mApi.isLogicalElement(element) || (element.element() != "Handler"))
			continue;

		eventHadlers += generateEventHandler(mApi.name(element)); // generate code for each event handler
	}
	return eventHadlers;
}

QString DispatcherGenerator::generateConstants(qReal::Id const &element) const
{
	QString result;
	foreach (Id const id, mApi.children(element)) {
		if (!mApi.isLogicalElement(id) || id.element() != "MasterDiagramConstant")
			continue;

		QString constantTemplate = mTemplateUtils["@@MasterDiagramConstant@@"];
		QString const name = mApi.name(id);
		QString const type = mApi.stringProperty(id, "type");
		QString const value = mApi.stringProperty(id, "value");
		constantTemplate.replace("@@Name@@", name)
				.replace("@@Type@@", type)
				.replace("@@Value@@", value)
				;

		result += constantTemplate;
	}
	return result;
}

QString DispatcherGenerator::generateFields(qReal::Id const &element) const
{
	QString result;
	foreach (Id const id, mApi.children(element)) {
		if (!mApi.isLogicalElement(id) || id.element() != "MasterDiagramField")
			continue;

		QString const name = mApi.name(id);
		QString const type = mApi.stringProperty(id, "type");
		QString const value = mApi.stringProperty(id, "defaultValue");
		bool const isStatic = mApi.property(id, "static").toBool();

		QString fieldTemplate = value.isEmpty()
				? mTemplateUtils["@@MasterDiagramFieldWithoutInit@@"]
				: mTemplateUtils["@@MasterDiagramField@@"];

		fieldTemplate.replace("@@Name@@", name)
				.replace("@@Type@@", type)
				.replace("@@Value@@", value)
				.replace("@@OptionalStatic@@", isStatic ? "static " : "")
				;

		result += fieldTemplate;
	}
	return result;
}

QString DispatcherGenerator::generateEventHandler(QString const handlerName)
{
	QString handlerCode = mTemplateUtils["@@EventHandler@@"];
	handlerCode.replace("@@HandlerName@@", handlerName);

	foreach (Id const diagram, mApi.elementsByType("UbiqActivityDiagram")) {
		// search for the diagram with name handlerName
		if (!mApi.isLogicalElement(diagram) || (mApi.name(diagram) != handlerName))
			continue;

		// diagram found, now get HandlerStart-s and generate cases

		QString cases;
		foreach (Id const &element, mApi.children(diagram)) {
			if (!mApi.isLogicalElement(diagram) || (element.element() != "HandlerStart"))
				continue;

			QString caseCode = mTemplateUtils["@@SwitchCase@@"];
			caseCode.replace("@@CaseValue@@", mApi.name(element));

			cases += caseCode;
		}
		handlerCode.replace("@@SwitchCases@@", cases);
	}

	return handlerCode;
}
<|endoftext|>