test_sdk/script/gtl_scr_engine.cpp

784 lines
23 KiB
C++

#include "gtl_scr_engine.h"
#include <QFileInfo>
#include "core/gtl_logger.h"
#include "core/gtl_device.h"
#include "core/gtl_analog_data.h"
#include "math/gtl_math_sum.h"
#include "math/gtl_math_rms.h"
#include "math/gtl_math_var.h"
#include "math/gtl_math_freq.h"
#include "math/gtl_math_ampl.h"
#include "math/gtl_math_kurt.h"
#include "math/gtl_math_delta_phase.h"
#include "math/gtl_math_delta_phase_spec.h"
#include "math/gtl_math_filter_iir.h"
#include "math/gtl_math_intg.h"
#include "math/gtl_math_diff.h"
#include "math/gtl_math.h"
#include "hw/gtl_hw_player_file_gtr.h"
#include "hw/gtl_hw_player_file_wav.h"
namespace gtl
{
namespace scr
{
QStringList engine::import_paths;
engine::engine(QObject* parent)
: QObject(parent)
, _engine(nullptr)
, _player(nullptr)
, _file(nullptr)
{
_log = new log(this);
connect(_log, &log::new_message, this, &engine::log_message);
}
engine::~engine()
{
set_file();
}
void gtl::scr::engine::clear()
{
clear_options();
clear_objects();
remove_all_ad();
}
void engine::get_state(QJsonObject &root) const
{
QJsonArray base_indices;
for(auto obj: _objects)
{
if(is_gtl_math_analog_value(obj))
base_indices.append(QJsonObject{{static_cast<gtl::math::analog_value*>(obj)->name(), static_cast<gtl::math::analog_value*>(obj)->value()}});
}
root.insert("base_indices", base_indices);
QJsonArray specs;
for(auto obj: _objects)
{
if(is_gtl_scr_spec(obj))
{
QJsonObject spec_object;
static_cast<spec*>(obj)->get_state(spec_object);
specs.append(spec_object);
}
}
root.insert("specs", specs);
}
bool engine::set_file(QString path, std::vector<int> channels)
{
// qDebug() << path;
if(_file)
{
delete _player;
_player = nullptr;
delete _file;
_file = nullptr;
for(auto it : _analog_inputs)
delete it;
_analog_inputs.clear();
}
clear();
if(path.isEmpty())
return true;
QFileInfo info(path);
if(info.suffix().toLower() == "gtr")
_file = new gtl::hw::player_file_gtr(this, path);
else if(info.suffix().toLower() == "wav")
_file = new gtl::hw::player_file_wav(this, path);
if(_file == nullptr)
{
gtl::logger::error("script engine", "error opening file: " + path);
return false;
}
if(!_file->is_ok())
{
gtl::logger::error("script engine", "error reading file: " + path);
delete _file;
_file = nullptr;
return false;
}
if(channels.empty())
{
for(int i = 0; i < _file->channels(); i++)
{
gtl::analog_data* ad = new analog_data(_file->rate(), _file->reference(i));
ad->set_name(_file->channel(i));
_analog_inputs.push_back(ad);
}
}
else
{
for(auto index: channels)
{
gtl::analog_data* ad = new analog_data(_file->rate(), _file->reference(index));
ad->set_name(_file->channel(index));
_analog_inputs.push_back(ad);
}
}
emit analog_inputs_changed();
_player = new player(_file, channels, this);
connect(_player, &player::data_read, this, &engine::set_data_from_file/*, Qt::DirectConnection*/);
return true;
}
QQmlEngine *engine::qml_engine() const
{
return _engine;
}
void engine::set_ad(std::vector<gtl::analog_data*>::iterator begin, std::vector<gtl::analog_data*>::iterator end)
{
remove_all_ad();
for(auto it = begin; it != end; it++)
add_ad(*it);
}
void engine::add_local_import_path(QString path)
{
_local_import_paths.push_back(path);
}
void engine::clear_local_import_paths()
{
_local_import_paths.clear();
}
analog_data *engine::analog_input(int idx)
{
return qobject_cast<analog_data*>(_analog_inputs[idx]);
}
bool engine::evaluate(QString program)
{
clear_objects();
if(_engine)
delete _engine;
_engine = new QQmlEngine(this);
init();
QJSValue result = _engine->evaluate(program);
if(result.isError())
gtl::logger::error("script", result.toString() + " " + tr("at line") + ": " + result.property("lineNumber").toString() + " " + tr("in file") + ": " + result.property("fileName").toString());
bool res = !result.isError();
if(res && _player)
{
_player->stop();
_player->start();
}
return res;
}
void engine::clear_options()
{
_options = QJsonObject();
}
void engine::set_options(const QJsonObject &root)
{
_options = root;
emit options_changed();
}
void engine::get_results(QJsonObject &root)
{
root = _results;
}
QVariant engine::get_analog_inputs() const
{
return QVariant::fromValue(_analog_inputs);
}
bool engine::is_type(QObject *obj, QString type) const
{
if(obj == NULL)
return false;
const QMetaObject* meta_object = obj->metaObject();
while(meta_object)
{
if(QString(meta_object->className()) == type)
return true;
meta_object = meta_object->superClass();
}
return false;
}
bool engine::is_gtl_analog_data(QObject *obj)
{
return is_type(obj, "gtl::analog_data");
}
bool engine::is_gtl_math_analog_value(QObject *obj) const
{
return is_type(obj, "gtl::math::analog_value");
}
bool engine::is_gtl_scr_spec(QObject *obj) const
{
return is_type(obj, "gtl::scr::spec");
}
log* engine::get_log() const
{
return _log;
}
QJsonObject engine::get_options() const
{
return _options;
}
QJsonObject engine::get_results() const
{
//return QVariant::fromValue(_results);
return _results;
}
void engine::clear_objects()
{
while(!_objects.empty())
{
QObject *obj = _objects.first();
_objects.removeFirst();
delete obj;
}
}
void engine::init()
{
_engine->globalObject().setProperty("gtl", _engine->newQObject(this));
_engine->globalObject().property("gtl").setProperty("filter_iir", _engine->newQMetaObject(&gtl::math::filter_iir::staticMetaObject));
_engine->globalObject().property("gtl").setProperty("spec", _engine->newQMetaObject(&gtl::scr::spec::staticMetaObject));
}
void engine::add_ad(gtl::analog_data *ad)
{
gtl::data_model_node *device = ad->root();
auto it = std::find_if(_analog_inputs.begin(), _analog_inputs.end(), [=](QObject* ai){return static_cast<analog_data*>(ai)->root() == device;});
if(it == _analog_inputs.end())
connect(static_cast<gtl::device*>(device), &gtl::device::recieved_data, this, &engine::device_recieved_data);
_analog_inputs.push_back(ad);
connect(ad, &gtl::data_model_node::deleting, this, &engine::deleting_ad);
emit analog_inputs_changed();
}
void engine::remove_ad(gtl::analog_data *ad)
{
_analog_inputs.removeOne(ad);
gtl::data_model_node *device = ad->root();
auto it = std::find_if(_analog_inputs.begin(), _analog_inputs.end(), [=](QObject* ai){return static_cast<analog_data*>(ai)->root() == device;});
if(it == _analog_inputs.end())
disconnect(static_cast<gtl::device*>(device), &gtl::device::recieved_data, this, &engine::device_recieved_data);
emit analog_inputs_changed();
}
void engine::remove_all_ad()
{
for(auto it : _analog_inputs)
disconnect(static_cast<gtl::device*>(static_cast<analog_data*>(it)->root()), &gtl::device::recieved_data, this, &engine::device_recieved_data);
_analog_inputs.clear();
emit analog_inputs_changed();
}
QJSValue engine::add_value_sum(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::sum* sum_value = NULL;
if(is_gtl_analog_data(obj))
{
sum_value = new gtl::math::sum(static_cast<gtl::analog_data*>(obj));
_objects.push_back(sum_value);
}
else
gtl::logger::error("script", "error creating sum_value object: parent is not gtl::analog_data object");
emit base_index_created(sum_value);
return _engine->newQObject(sum_value);
}
QJSValue engine::add_value_rms(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::rms* rms_value = NULL;
if(is_gtl_analog_data(obj))
{
rms_value = new gtl::math::rms(static_cast<gtl::analog_data*>(obj));
_objects.push_back(rms_value);
}
else
gtl::logger::error("script", "error creating rms_value object: parent is not gtl::analog_data object");
emit base_index_created(rms_value);
return _engine->newQObject(rms_value);
}
QJSValue engine::add_value_var(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::var* var_value = NULL;
if(is_gtl_analog_data(obj))
{
var_value = new gtl::math::var(static_cast<gtl::analog_data*>(obj));
_objects.push_back(var_value);
}
else
gtl::logger::error("script", "error creating rms_value object: parent is not gtl::analog_data object");
emit base_index_created(var_value);
return _engine->newQObject(var_value);
}
QJSValue engine::add_value_freq(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::freq* freq_value = NULL;
if(is_gtl_analog_data(obj))
{
freq_value = new gtl::math::freq(static_cast<gtl::analog_data*>(obj));
_objects.push_back(freq_value);
}
else
gtl::logger::error("script", "error creating freq_value object: parent is not gtl::analog_data object");
emit base_index_created(freq_value);
return _engine->newQObject(freq_value);
}
QJSValue engine::add_value_ampl(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::ampl* ampl_value = NULL;
if(is_gtl_analog_data(obj))
{
ampl_value = new gtl::math::ampl(static_cast<gtl::analog_data*>(obj));
_objects.push_back(ampl_value);
}
else
gtl::logger::error("script", "error creating freq_value object: parent is not gtl::analog_data object");
emit base_index_created(ampl_value);
return _engine->newQObject(ampl_value);
}
QJSValue engine::add_value_kurt(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::kurt* kurt_value = NULL;
if(is_gtl_analog_data(obj))
{
kurt_value = new gtl::math::kurt(static_cast<gtl::analog_data*>(obj));
_objects.push_back(kurt_value);
}
else
gtl::logger::error("script", "error creating freq_value object: parent is not gtl::analog_data object");
emit base_index_created(kurt_value);
return _engine->newQObject(kurt_value);
}
QJSValue engine::add_delta_phase(QJSValue parent, QJSValue parent1)
{
QObject* obj = parent.toQObject();
QObject* obj1 = parent1.toQObject();
gtl::math::delta_phase* delta_phase = NULL;
if(is_gtl_analog_data(obj) && is_gtl_analog_data(obj1))
{
delta_phase = new gtl::math::delta_phase(static_cast<gtl::analog_data*>(obj), static_cast<gtl::analog_data*>(obj1));
_objects.push_back(delta_phase);
}
else
gtl::logger::error("script", "error creating delta_phase object: parent is not gtl::analog_data object");
return _engine->newQObject(delta_phase);
}
QJSValue engine::add_delta_phase_spec(QJSValue parent, QJSValue parent1)
{
QObject* obj = parent.toQObject();
QObject* obj1 = parent1.toQObject();
gtl::math::delta_phase_spec* delta_phase = NULL;
if(is_gtl_analog_data(obj) && is_gtl_analog_data(obj1))
{
delta_phase = new gtl::math::delta_phase_spec(static_cast<gtl::analog_data*>(obj), static_cast<gtl::analog_data*>(obj1));
_objects.push_back(delta_phase);
}
else
gtl::logger::error("script", "error creating delta_phase object: parent is not gtl::analog_data object");
return _engine->newQObject(delta_phase);
}
QJSValue engine::add_filter_iir(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::filter_iir* filter_iir = NULL;
if(is_gtl_analog_data(obj))
{
filter_iir = new gtl::math::filter_iir(static_cast<gtl::analog_data*>(obj), true);
_objects.push_back(static_cast<QObject*>(filter_iir));
connect(filter_iir, &gtl::data_model_node::deleting, this, &engine::deleting_object);
}
else
gtl::logger::error("script", "error creating filter object: parent is not gtl::analog_data object");
return _engine->newQObject(filter_iir);
}
QJSValue engine::add_intg(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::intg *intg = NULL;
if(is_gtl_analog_data(obj))
{
intg = new gtl::math::intg(static_cast<gtl::analog_data*>(obj), true);
_objects.push_back(static_cast<QObject*>(intg));
connect(intg, &gtl::data_model_node::deleting, this, &engine::deleting_object);
}
else
gtl::logger::error("script", "error creating filter object: parent is not gtl::analog_data object");
return _engine->newQObject(intg);
}
QJSValue engine::add_diff(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::math::diff *diff = NULL;
if(is_gtl_analog_data(obj))
{
diff = new gtl::math::diff(static_cast<gtl::analog_data*>(obj), true);
_objects.push_back(static_cast<QObject*>(diff));
connect(diff, &gtl::data_model_node::deleting, this, &engine::deleting_object);
}
else
gtl::logger::error("script", "error creating filter object: parent is not gtl::analog_data object");
return _engine->newQObject(diff);
}
QJSValue engine::add_ausp(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::scr::spec* ausp = NULL;
if(is_gtl_analog_data(obj))
{
ausp = new gtl::scr::spec(gtl::math::spec::ausp, static_cast<gtl::analog_data*>(obj));
_objects.push_back(static_cast<QObject*>(ausp));
connect(ausp, &gtl::math::spec::deleting, this, &engine::deleting_object);
connect(ausp, &gtl::scr::spec::create_engine_object, this, &engine::create_jsobject);
emit spec_created(ausp);
}
else
gtl::logger::error("script", "error creating ausp object: parent is not gtl::analog_data object");
return _engine->newQObject(ausp);
}
QJSValue engine::add_spen(QJSValue parent)
{
QObject* obj = parent.toQObject();
gtl::scr::spec* spen = NULL;
if(is_gtl_analog_data(obj))
{
spen = new gtl::scr::spec(gtl::math::spec::spen, static_cast<gtl::analog_data*>(obj));
_objects.push_back(static_cast<QObject*>(spen));
connect(spen, &gtl::math::spec::deleting, this, &engine::deleting_object);
connect(spen, &gtl::scr::spec::create_engine_object, this, &engine::create_jsobject);
emit spec_created(spen);
}
else
gtl::logger::error("script", "error creating spen object: parent is not gtl::analog_data object");
return _engine->newQObject(spen);
}
QJSValue engine::get_analog_input(QString name)
{
QObject *input = NULL;
auto it = std::find_if(_analog_inputs.begin(), _analog_inputs.end(), [=](QObject *obj){return static_cast<gtl::analog_data*>(obj)->name() == name;});
if(it != _analog_inputs.end())
input = *it;
return _engine->newQObject(input);
}
QJSValue engine::import(QString file_name)
{
if(QFileInfo::exists(file_name))
return _engine->importModule(file_name);
for(auto it : _local_import_paths)
{
QFileInfo file(it + "/" + file_name);
if(file.exists())
{
return _engine->importModule(file.absoluteFilePath());
}
}
for(auto it : import_paths)
{
QFileInfo file(it + "/" + file_name);
if(file.exists())
{
return _engine->importModule(file.absoluteFilePath());
}
}
gtl::logger::error("script", tr("can't find module file: ") + file_name);
return QJSValue();
}
qreal engine::get_kurt_value(const QJsonArray &data_array) const
{
std::vector<qreal> array;
for(auto it = data_array.cbegin(); it != data_array.cend(); it++)
array.push_back(it->toDouble());
return mathFunctions::kurt(array.begin(), array.end());
}
qreal engine::get_var_value(const QJsonArray &data_array) const
{
std::vector<qreal> array;
for(auto it = data_array.cbegin(); it != data_array.cend(); it++)
array.push_back(it->toDouble());
return mathFunctions::var(array.begin(), array.end());
}
void engine::device_recieved_data()
{
}
void engine::deleting_ad()
{
remove_ad(static_cast<gtl::analog_data*>(sender()));
}
void engine::deleting_object()
{
_objects.removeOne(sender());
}
void engine::create_jsobject(QObject *obj, QJSValue &js_object)
{
js_object = _engine->newQObject(obj);
}
void engine::set_results(const QJsonObject &value)
{
_results = value;
emit results_changed();
}
void engine::set_data_from_file()
{
for(int i = 0; i < _analog_inputs.size(); i++)
static_cast<analog_data*>(_analog_inputs[i])->set_data(_player->data(), _player->samples(), _player->channels().empty() ? i : _player->channels().at(i), /*_analog_inputs.size()*/_file->channels());
device_recieved_data();
_player->confirm();
}
log::log(QObject *parent)
: QObject(parent)
{
}
void log::info(QString tag, QString message)
{
gtl::logger::info(tag, message);
emit new_message(tag, message);
}
void log::warning(QString tag, QString message)
{
gtl::logger::warning(tag, message);
emit new_message(tag, message);
}
void log::error(QString tag, QString message)
{
gtl::logger::error(tag, message);
emit new_message(tag, message);
}
void log::debug(QString tag, QString message)
{
gtl::logger::debug(tag, message);
emit new_message(tag, message);
}
player::player(hw::player_file *file, const std::vector<int> &channels, QObject *parent)
: QThread(parent)
, _file(file)
, _samples(qRound(0.1*file->rate()))
, _buffer(_samples * file->channels())
, _channels(channels)
{
}
player::~player()
{
stop();
}
void player::start()
{
_is_playing = true;
QThread::start();
}
void player::stop()
{
if(!isRunning())
return;
_status = true;
_is_playing = false;
wait();
}
qreal player::rate() const
{
return _file->rate();
}
void player::confirm()
{
_status = true;
}
int player::samples() const
{
return _samples;
}
qreal *player::data() const
{
return (qreal*)&_buffer[0];
}
const std::vector<int> &player::channels() const
{
return _channels;
}
void player::run()
{
setPriority(QThread::LowPriority);
int idx = 0;
while(_is_playing)
{
_file->get_data(&_buffer[0], idx, _samples, true);
if(_samples)
{
_status = false;
emit data_read();
// qDebug() << "playing...";
}
while((!_status) && _is_playing)
msleep(1);
}
}
}
}