#include "gtl_hw_player_file_wav.h" #include "qmath.h" namespace gtl { namespace hw { player_file_wav::player_file_wav(QObject *parent, QString path) : player_file(parent, path) { if (!_is_ok) return; _is_ok = false; quint32 id_chunk; quint32 size_chunk; *_stream >> id_chunk; if (id_chunk != 0x46464952 && id_chunk != 0x34365742) return; *_stream >> size_chunk; // if (size_chunk != _file->size() - _file->pos()) // return; *_stream >> id_chunk; if (id_chunk != 0x45564157) return; while (!_stream->atEnd()) { *_stream >> id_chunk; if (id_chunk == 0x20746d66) { read_fmt_chunk(); if (_format != 1 && _format != 3) return; } else if (id_chunk == 0x61746164) { read_data_chunk(); break; } else if (id_chunk == 0x34367364) { read_ds64_chunk(); } else { read_unknown_chunk(); } } _file->seek(_pos_data + _size_data); _time = (qreal)_size_data / _block_align / _rate; _info = tr("rate: ") + QString::number(_rate, 'f', 0) + tr(" hz") + ";\r\n"; _info += tr("time: ") + QString::number(_time) + tr(" sec") + ";\r\n"; _info += tr("bits per sample: ") + QString::number(_bits_per_sample) + ";\r\n"; _info += "\r\n" + comment(); _is_ok = true; } player_file_wav::~player_file_wav() { } bool player_file_wav::get_data(qreal *data, int &samples, bool is_cyclic, bool &is_continued) { quint64 smps = 0; QByteArray buffer(samples * _block_align, 0); while (smps < samples) { quint64 smps_to_end = (_pos_data + _size_data - _file->pos()) / _block_align; if (smps_to_end < (samples - smps)) { int bytes = _stream->readRawData((char*)&buffer.data()[smps*_block_align], smps_to_end*_block_align); if (bytes < 0) return false; smps += bytes / _block_align; _file->seek(_pos_data); if (!is_cyclic) { samples = smps; is_continued = false; break; } } else { int bytes = _stream->readRawData((char*)&buffer.data()[smps*_block_align], (samples - smps)*_block_align); if (bytes < 0) return false; smps += bytes / _block_align; } } qint32 sample; int bytes_per_sample = _block_align / channels(); int bits_shift = 32 - _bits_per_sample; qreal factor = qPow(2, bits_shift); for (int i = 0; i < samples * channels(); i++) { std::copy(&buffer.data()[i*bytes_per_sample], &buffer.data()[i*bytes_per_sample + bytes_per_sample], (char*)&sample); if (_bits_per_sample) sample -= 128; sample = sample << bits_shift; data[i] = 10.0 * sample / (sample < 0 ? 2147483648 : 2147483647); } return true; } bool player_file_wav::get_data(qreal *data, int &idx, int &samples, bool is_cyclic /*= false*/) { _mutex.lock(); quint64 smps = 0; _file->seek(_pos_data + idx*_block_align); QByteArray buffer(samples * _block_align, 0); while (smps < samples) { quint64 smps_to_end = (_pos_data + _size_data - _file->pos()) / _block_align; if (smps_to_end < (samples - smps)) { int bytes = _stream->readRawData((char*)&buffer.data()[smps*_block_align], smps_to_end*_block_align); if (bytes <= 0) { _mutex.unlock(); samples = smps; return false; } smps += bytes / _block_align; if (!is_cyclic) { samples = smps; break; } else _file->seek(_pos_data); } else { int bytes = _stream->readRawData((char*)&buffer.data()[smps*_block_align], (samples - smps)*_block_align); if (bytes < 0) { _mutex.unlock(); samples = smps; return false; } smps += bytes / _block_align; } } qint32 sample; int bytes_per_sample = _block_align / channels(); int bits_shift = 32 - _bits_per_sample; qreal factor = qPow(2, bits_shift); for (int i = 0; i < samples * channels(); i++) { std::copy(&buffer.data()[i*bytes_per_sample], &buffer.data()[i*bytes_per_sample + bytes_per_sample], (char*)&sample); if (_format == 3) { data[i] = *((float*)&sample); } else { if (_bits_per_sample) sample -= 128; sample = sample << bits_shift; data[i] = 10.0 * sample / (sample < 0 ? 2147483648 : 2147483647); } } int pos = _file->pos(); int size = _pos_data + _size_data; bool is_compete = _file->pos() == _pos_data + _size_data; if (is_compete) seek_to_start(); idx = (_file->pos() - _pos_data) / _block_align; _mutex.unlock(); return is_compete && !is_cyclic; } void player_file_wav::read_fmt_chunk() { quint32 size_chunk; *_stream >> size_chunk; quint64 pos_chunk = _file->pos(); quint32 tmp_32; quint16 tmp_16; *_stream >> _format; if (_format == 1 || _format == 3) { *_stream >> tmp_16; _channels = tmp_16; *_stream >> tmp_32; _rate = tmp_32; *_stream >> tmp_32; // avg bytes per second *_stream >> _block_align; *_stream >> _bits_per_sample; } _file->seek(pos_chunk + size_chunk); } void player_file_wav::read_data_chunk() { quint32 size; *_stream >> size; if (size != 0xffffffff) _size_data = size; _pos_data = _file->pos(); // _stream->skipRawData(_size_data); } void player_file_wav::read_ds64_chunk() { quint32 high; quint32 low; quint32 size; *_stream >> size; *_stream >> low; *_stream >> high; *_stream >> low; *_stream >> high; _size_data = low + ((quint64)high << 32); *_stream >> low; *_stream >> high; *_stream >> low; } void player_file_wav::read_unknown_chunk() { quint32 size; *_stream >> size; _stream->skipRawData(size); } } }