app/lib: keep data chunked

This commit is contained in:
itsmattkc 2022-07-11 08:04:47 -07:00
parent 68926a5afe
commit 7ef15f4e42
7 changed files with 109 additions and 60 deletions

View file

@ -61,6 +61,8 @@ MainWindow::MainWindow(QWidget *parent) :
InitializeMenuBar();
splitter->setSizes({99999, 99999});
setWindowTitle(tr("SI Editor"));
}
void MainWindow::OpenFilename(const QString &s)
@ -127,7 +129,8 @@ void MainWindow::ExtractObject(si::Object *obj)
if (!s.isEmpty()) {
QFile f(s);
if (f.open(QFile::WriteOnly)) {
f.write(obj->data().data(), obj->data().size());
bytearray b = obj->GetNormalizedData();
f.write(b.data(), b.size());
f.close();
} else {
QMessageBox::critical(this, QString(), tr("Failed to write to file \"%1\".").arg(s));

View file

@ -28,7 +28,8 @@ void BitmapPanel::OnOpeningData(void *data)
{
si::Object *o = static_cast<si::Object*>(data);
QByteArray b(o->data().data(), o->data().size());
si::bytearray processed = o->GetNormalizedData();
QByteArray b(processed.data(), processed.size());
QBuffer buf(&b);
QImage img;
img.load(&buf, "BMP");

View file

@ -40,20 +40,8 @@ void WavPanel::OnOpeningData(void *data)
si::Object *o = static_cast<si::Object*>(data);
// Find fmt and data
auto dat = o->data().data();
for (size_t i=0; i<o->data().size(); i++) {
if (!memcmp(dat+i, "fmt ", 4)) {
header_ = *(si::WAVFormatHeader *)(dat+i+8);
break;
}
}
for (size_t i=0; i<o->data().size(); i++) {
if (!memcmp(dat+i, "data", 4)) {
uint32_t sz = *(uint32_t*)(dat+i+4);
playhead_slider_->setMaximum(sz/GetSampleSize());
break;
}
}
header_ = *o->GetFileHeader().cast<si::WAVFormatHeader>();
playhead_slider_->setMaximum(o->GetFileBodySize()/GetSampleSize());
}
void WavPanel::OnClosingData(void *data)
@ -71,37 +59,20 @@ void WavPanel::Play(bool e)
{
if (audio_out_) {
audio_out_->stop();
//audio_out_->deleteLater();
delete audio_out_;
audio_out_ = nullptr;
}
buffer_.close();
array_.clear();
playback_timer_->stop();
if (e) {
const si::bytearray &lib = static_cast<si::Object*>(GetData())->data();
array_ = QByteArray(lib.data(), lib.size());
si::Object *o = static_cast<si::Object*>(GetData());
si::bytearray pcm = o->GetFileBody();
array_ = QByteArray(pcm.data(), pcm.size());
buffer_.open(QBuffer::ReadOnly);
size_t start = 0;
si::WAVFormatHeader header;
// Find fmt and data
auto dat = lib.data();
for (size_t i=0; i<lib.size(); i++) {
if (!memcmp(dat+i, "fmt ", 4)) {
header = *(si::WAVFormatHeader *)(dat+i+8);
break;
}
}
for (size_t i=0; i<lib.size(); i++) {
if (!memcmp(dat+i, "data", 4)) {
start = i + 8;
break;
}
}
buffer_start_ = start;
if (playhead_slider_->value() < playhead_slider_->maximum()) {
start += playhead_slider_->value() * GetSampleSize();
@ -110,9 +81,9 @@ void WavPanel::Play(bool e)
buffer_.seek(start);
QAudioFormat audio_fmt;
audio_fmt.setSampleRate(header.SampleRate);
audio_fmt.setChannelCount(header.Channels);
audio_fmt.setSampleSize(header.BitsPerSample);
audio_fmt.setSampleRate(header_.SampleRate);
audio_fmt.setChannelCount(header_.Channels);
audio_fmt.setSampleSize(header_.BitsPerSample);
audio_fmt.setByteOrder(QAudioFormat::LittleEndian);
audio_fmt.setCodec(QStringLiteral("audio/pcm"));
audio_fmt.setSampleType(QAudioFormat::SignedInt);
@ -127,7 +98,7 @@ void WavPanel::Play(bool e)
void WavPanel::TimerUpdate()
{
playhead_slider_->setValue((buffer_.pos() - buffer_start_) / GetSampleSize());
playhead_slider_->setValue(buffer_.pos() / GetSampleSize());
}
void WavPanel::OutputChanged(QAudio::State state)
@ -141,6 +112,6 @@ void WavPanel::OutputChanged(QAudio::State state)
void WavPanel::SliderMoved(int i)
{
if (buffer_.isOpen()) {
buffer_.seek(buffer_start_ + i * GetSampleSize());
buffer_.seek(i * GetSampleSize());
}
}

View file

@ -30,9 +30,9 @@ private:
QAudioOutput *audio_out_;
QBuffer buffer_;
QByteArray array_;
size_t buffer_start_;
QTimer *playback_timer_;
si::WAVFormatHeader header_;
QByteArray play_buffer_;
private slots:
void Play(bool e);

View file

@ -90,7 +90,7 @@ bool Interleaf::ParseStream(Chunk *chunk)
for (ChunkMap::const_iterator it=data.begin(); it!=data.end(); it++) {
Object *o = obj->FindSubObjectWithID(it->first);
if (o) {
o->ProcessData(it->second);
o->SetChunkedData(it->second);
} else {
std::cout << "Failed to find object with ID " << it->first << std::endl;
}

View file

@ -47,28 +47,40 @@ bool Object::Parse(Chunk *chunk)
return true;
}
void Object::ProcessData(const std::vector<bytearray> &chunks)
bytearray Object::GetNormalizedData() const
{
switch (filetype_) {
return ToPackedData(filetype(), data_);
}
void Object::SetNormalizedData(const bytearray &d)
{
SetChunkedData(ToChunkedData(filetype(), d));
}
bytearray Object::ToPackedData(MxOb::FileType filetype, const ChunkedData &chunks)
{
bytearray data;
switch (filetype) {
case MxOb::WAV:
{
// Make space for WAVE header
data_.resize(0x2C);
data.resize(0x2C);
// Merge all chunks after the first one
for (size_t i=1; i<chunks.size(); i++) {
data_.append(chunks[i]);
data.append(chunks[i]);
}
// Copy boilerplate bytes for header
uint32_t *header = reinterpret_cast<uint32_t *>(data_.data());
uint32_t *header = reinterpret_cast<uint32_t *>(data.data());
header[0] = Chunk::TYPE_RIFF; // "RIFF"
header[1] = data_.size() - 8; // Size of total file
header[1] = data.size() - 8; // Size of total file
header[2] = 0x45564157; // "WAVE"
header[3] = 0x20746D66; // "fmt "
header[4] = 16; // Size of fmt chunk
header[9] = 0x61746164; // "data"
header[10] = data_.size() - 0x2C; // Size of data chunk
header[10] = data.size() - 0x2C; // Size of data chunk
// Copy fmt header from chunk 1
memcpy(&header[5], chunks[0].data(), 16);
@ -77,27 +89,77 @@ void Object::ProcessData(const std::vector<bytearray> &chunks)
case MxOb::STL:
{
// Make space for BMP header
data_.resize(14);
data.resize(14);
// Merge all chunks after the first one
for (size_t i=0; i<chunks.size(); i++) {
data_.append(chunks[i]);
data.append(chunks[i]);
}
// Set BM identifier
*(uint16_t *)(data_.data()) = 0x4D42;
*(uint16_t *)(data.data()) = 0x4D42;
// Set file size
*(uint32_t*)(data_.data()+2) = data_.size();
*(uint32_t*)(data.data()+2) = data.size();
// Set reserved bytes
*(uint32_t*)(data_.data()+6) = 0;
*(uint32_t*)(data.data()+6) = 0;
// Set offset
*(uint32_t*)(data_.data()+10) = chunks.at(0).size() + 14;
*(uint32_t*)(data.data()+10) = chunks.at(0).size() + 14;
break;
}
}
return data;
}
Object::ChunkedData Object::ToChunkedData(MxOb::FileType filetype, const bytearray &chunks)
{
// FIXME: STUB
return ChunkedData();
}
bytearray Object::GetFileHeader() const
{
switch (filetype()) {
case MxOb::WAV:
case MxOb::STL:
return data_.at(0);
}
return bytearray();
}
bytearray Object::GetFileBody() const
{
bytearray b;
switch (filetype()) {
case MxOb::WAV:
case MxOb::STL:
for (size_t i=1; i<data_.size(); i++) {
b.append(data_.at(i));
}
break;
}
return b;
}
size_t Object::GetFileBodySize() const
{
size_t s = 0;
switch (filetype()) {
case MxOb::WAV:
case MxOb::STL:
for (size_t i=1; i<data_.size(); i++) {
s += data_.at(i).size();
}
break;
}
return s;
}
Object *Object::FindSubObjectWithID(uint32_t id)

View file

@ -10,16 +10,28 @@ namespace si {
class Object : public Core
{
public:
using ChunkedData = std::vector<bytearray>;
Object();
bool Parse(Chunk *chunk);
void ProcessData(const std::vector<bytearray> &chunks);
void SetChunkedData(const ChunkedData &cd) { data_ = cd; }
LIBWEAVER_EXPORT bytearray GetNormalizedData() const;
LIBWEAVER_EXPORT void SetNormalizedData(const bytearray &d);
LIBWEAVER_EXPORT static bytearray ToPackedData(MxOb::FileType filetype, const ChunkedData &chunks);
LIBWEAVER_EXPORT static ChunkedData ToChunkedData(MxOb::FileType filetype, const bytearray &chunks);
LIBWEAVER_EXPORT bytearray GetFileHeader() const;
LIBWEAVER_EXPORT bytearray GetFileBody() const;
LIBWEAVER_EXPORT size_t GetFileBodySize() const;
const MxOb::FileType &filetype() const { return filetype_; }
const uint32_t &id() const { return id_; }
const std::string &name() const { return name_; }
const std::string &filename() const { return filename_; }
bytearray &data() { return data_; }
const ChunkedData &data() const { return data_; }
Object *FindSubObjectWithID(uint32_t id);
@ -46,7 +58,7 @@ private:
uint32_t unknown30_;
uint32_t unknown31_;
bytearray data_;
ChunkedData data_;
};