#include "gtl_hw_player.h" #include #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 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 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 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> 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>::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>::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 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; } } } }