test_sdk/hw/gtl_hw_player.cpp

378 lines
11 KiB
C++
Raw Normal View History

#include "gtl_hw_player.h"
#include <QDateTime>
#include "hw/gtl_hw_player_file_gtr.h"
#include "hw/gtl_hw_player_file_wav.h"
#include "hw/gtl_hw_player_analog_input.h"
namespace gtl
{
namespace hw
{
class contain
{
private:
int _idx;
public:
contain(int idx) : _idx(idx) {}
bool operator()(const std::pair<int, int> range) const { return _idx >= range.first && _idx < range.second; }
};
class greater
{
private:
int _idx;
public:
greater(int idx) : _idx(idx) {}
bool operator()(const std::pair<int, int> range) const { return _idx < range.first; }
};
player::player(QObject* parent)
: device{parent}
, _file(NULL)
, _is_cyclic(false)
, _time(0)
, _speed_factor(1)
, _sampling(1)
{
_device->set_name(tr("player"));
}
QString player::type() const
{
return "player";
}
bool player::start(QString id, qreal rate)
{
stop();
if(_id != id)
{
_id = id;
/*
//_device->remove_children();
while(_device->count() != 0)
{
data_model_node* child = _device->child(0);
// _device->remove(child);
delete child;
}
*/
_device->clear();
if(_file)
{
delete _file;
_file = NULL;
}
QFileInfo info(_id);
if(info.suffix().toLower() == "gtr")
_file =new player_file_gtr(this, _id);
else if(info.suffix().toLower() == "wav")
_file =new player_file_wav(this, _id);
if(_file)
{
if(!_file->is_ok())
{
delete _file;
_file = NULL;
}
}
if(_file)
{
_rate = _file->rate()/_sampling;
for(int i = 0;i < _file->channels(); i++)
_device->add_ai(new player_analog_input(_rate, _file->channel_info(i), _device));
_count_ai = _file->channels();
_device->set_name(tr("player") + "[" + info.fileName() + "]");
}
else
{
_rate = 0;
_device->set_name(tr("player"));
}
_device->set_id(id);
_device->set_rate(_rate);
_time = 0;
}
else if(_file)
{
// if(_rate != _file->rate()/_sampling)
{
_rate = _file->rate()/_sampling;
for(int i = 0; i < _file->channels(); i++)
ai(i)->set_rate(_rate);
_device->set_rate(_rate);
}
}
if(_file && rate == 0)
{
QThread::start(QThread::HighPriority);
}
return true;
}
void player::save(QDomElement &root_element)
{
_rate = -1;
device::save(root_element);
}
player_file *player::file() const
{
return _file;
}
void player::run()
{
qDebug() << "starting playing";
_is_continue = true;
_is_suspended = false;
quint64 last_time = QDateTime::currentMSecsSinceEpoch();
qreal dt = 1.0 /_file->rate();
std::vector<qreal> buffer;
int idx = 0;
_time = 0;
_pos = 0;
quint64 intervalms = 100;
int sampling_idx = 0;
_ranges_indices.clear();
_file->get_ranges_indices(std::back_inserter(_ranges_indices));
while(_is_continue)
{
quint64 current_time = QDateTime::currentMSecsSinceEpoch();
quint64 time = current_time - last_time;
if(time >= intervalms/1/*00*/)
{
if (!_is_suspended)
{
int samples = qRound(intervalms/dt/1000*_speed_factor);
//buffer.resize(samples * _file->channels());
buffer.clear();
//bool is_complete = _file->get_data(&buffer[0], idx, samples, _is_cyclic);
bool is_complete = get_data(idx, samples, _is_cyclic, std::back_inserter(buffer));
if(_sampling != 1)
{
int cnt = 0;
for(int i = sampling_idx; i < samples; i += _sampling)
{
for(int j = 0; j < _file->channels(); j++)
buffer[cnt* _file->channels() + j] = buffer[i*_file->channels() + j];
cnt++;
}
sampling_idx = _sampling - 1 - (samples - sampling_idx)%_sampling;
samples = cnt;
// qDebug() << sampling_idx << samples;
}
if(samples)
{
set_ai_data(&buffer[0], /*(int)buffer.size()*/samples*_file->channels());
emit received_data();
}
_time += samples*dt;
_pos = idx*dt;
if(is_complete)
{
if(/*idx == 0*/!_is_cyclic)
_time = total_time();
break;
}
}
last_time = current_time;
}
else
{
QThread::msleep(10);
}
}
}
bool player::get_data(int &idx, int &samples, bool is_cyclic, std::back_insert_iterator<std::vector<qreal>> data)
{
if (_file == NULL)
{
samples = 0;
return true;
}
_buffer_tmp.resize(samples*_file->channels());
if (_buffer_tmp.empty())
{
samples = 0;
return true;
}
int samples_total = samples;
int samples_readed = 0;
bool is_completed = false;
while (samples_readed < samples_total)
{
int idx_start = idx;
std::vector<std::pair<int, int>>::const_iterator iter_range_start = std::find_if(_ranges_indices.begin(), _ranges_indices.end(), contain(idx_start));
if (iter_range_start == _ranges_indices.end())
{
iter_range_start = std::find_if(_ranges_indices.begin(), _ranges_indices.end(), greater(idx_start));
if (iter_range_start == _ranges_indices.end())
{
if (is_cyclic)
iter_range_start = std::find_if(_ranges_indices.begin(), _ranges_indices.end(), greater(0));
else
{
is_completed = true;
break;
}
}
idx_start = iter_range_start->first;
}
int idx_stop = idx_start + samples;
std::vector<std::pair<int, int>>::const_iterator iter_range_stop = std::find_if(_ranges_indices.begin(), _ranges_indices.end(), contain(idx_stop));
if (iter_range_stop != iter_range_start)
idx_stop = iter_range_start->second;
idx = idx_start;
int samples_read = idx_stop - idx_start;
if (samples_readed + samples_read > samples_total)
samples_read = samples_total - samples_readed;
is_completed = _file->get_data(&_buffer_tmp[0], idx, samples_read, is_cyclic);
std::copy(_buffer_tmp.begin(), _buffer_tmp.begin() + samples_read*_file->channels(), data);
samples_readed += samples_read;
if (is_completed)
break;
}
samples = samples_readed;
return is_completed;
}
qreal player::total_time()
{
if(_file == nullptr)
return 0;
_ranges_indices.clear();
_file->get_ranges_indices(std::back_inserter(_ranges_indices));
if(_ranges_indices.empty())
return _file->time();
qreal time = 0;
std::pair<int, int> range = _ranges_indices[0];
for(int i = 1; i < _ranges_indices.size(); i++)
{
if(range.second >= _ranges_indices[i].first)
{
range.second = std::max(range.second, _ranges_indices[i].second);
}
else
{
time += (range.second - range.first) / _file->rate();
range = _ranges_indices[i];
}
}
time += (range.second - range.first) / _file->rate();
return time;
}
void player::get_parameter(int idx, QVariant &value)
{
if(idx == 0)
value = total_time();
else if(idx == 1)
value = _time;
else if(idx == 2)
value = _is_cyclic;
else if(idx == 3)
value = _speed_factor;
else if(idx == 4 && _file)
value = QVariant(_file->data());
else if(idx == 5)
{
if(_file)
value = _file->rate() / _sampling;
else
value = 0;
}
else if(idx == 6)
value = _pos;
else if(idx == 7)
value = _uuid;
}
void player::set_parameter(int idx, const QVariant &value)
{
if(idx == 2)
_is_cyclic = value.toBool();
else if(idx == 3)
_speed_factor = value.toDouble();
else if(idx == 5)
{
if(_file)
_sampling = qRound(_file->rate()/value.toDouble());
else
_sampling = 1;
if(_sampling < 1)
_sampling = 1;
}
}
}
}