mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Add OGG converter
This commit is contained in:
parent
a6dbc90b78
commit
59e96befd0
9 changed files with 175 additions and 31 deletions
|
|
@ -15,7 +15,7 @@ struct Resource
|
||||||
std::string type;
|
std::string type;
|
||||||
|
|
||||||
~Resource() {
|
~Resource() {
|
||||||
std::cout << "Res deleted" << std::endl;
|
// std::cout << "Res deleted" << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,16 +75,28 @@ void EmulatorWindow::Draw()
|
||||||
|
|
||||||
ImGui::SeparatorText("Script control and debug");
|
ImGui::SeparatorText("Script control and debug");
|
||||||
|
|
||||||
if (ImGui::Button("Build"))
|
if (ImGui::Button("Generate pack"))
|
||||||
{
|
{
|
||||||
m_story.Build();
|
m_story.Build(false);
|
||||||
|
}
|
||||||
|
if (ImGui::Button("Build script"))
|
||||||
|
{
|
||||||
|
m_story.Build(true);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Build & Play"))
|
if (ImGui::Button("Play"))
|
||||||
{
|
{
|
||||||
|
m_story.Log("Play story");
|
||||||
m_story.Play();
|
m_story.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Stop"))
|
||||||
|
{
|
||||||
|
m_story.Log("Stop story");
|
||||||
|
m_story.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
WindowBase::EndDraw();
|
WindowBase::EndDraw();
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,12 @@ public:
|
||||||
virtual void DeleteResource(FilterIterator &it) = 0;
|
virtual void DeleteResource(FilterIterator &it) = 0;
|
||||||
|
|
||||||
// Node interaction
|
// Node interaction
|
||||||
virtual void Build() = 0;
|
virtual void Build(bool compileonly) = 0;
|
||||||
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) = 0;
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) = 0;
|
||||||
virtual std::string GetNodeEntryLabel(const std::string &nodeId) = 0;
|
virtual std::string GetNodeEntryLabel(const std::string &nodeId) = 0;
|
||||||
virtual void Play() = 0;
|
virtual void Play() = 0;
|
||||||
virtual void Ok() = 0;
|
virtual void Ok() = 0;
|
||||||
|
virtual void Stop() = 0;
|
||||||
virtual void Pause() = 0;
|
virtual void Pause() = 0;
|
||||||
virtual void Next() = 0;
|
virtual void Next() = 0;
|
||||||
virtual void Previous() = 0;
|
virtual void Previous() = 0;
|
||||||
|
|
|
||||||
|
|
@ -66,16 +66,13 @@ std::string MainWindow::GetFileNameFromMemory(uint32_t addr)
|
||||||
|
|
||||||
void MainWindow::Play()
|
void MainWindow::Play()
|
||||||
{
|
{
|
||||||
if (m_dbg.run_result == VM_FINISHED)
|
|
||||||
{
|
|
||||||
Build();
|
|
||||||
|
|
||||||
if (m_dbg.run_result == VM_READY)
|
if ((m_dbg.run_result == VM_READY) || (m_dbg.run_result == VM_FINISHED))
|
||||||
{
|
{
|
||||||
m_dbg.free_run = true;
|
m_dbg.free_run = true;
|
||||||
m_dbg.run_result = VM_OK; // actually starts the execution
|
m_dbg.run_result = VM_OK; // actually starts the execution
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Ok()
|
void MainWindow::Ok()
|
||||||
|
|
@ -83,6 +80,11 @@ void MainWindow::Ok()
|
||||||
m_eventQueue.push({VmEventType::EvOkButton});
|
m_eventQueue.push({VmEventType::EvOkButton});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::Stop()
|
||||||
|
{
|
||||||
|
m_eventQueue.push({VmEventType::EvOkButton});
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::Pause()
|
void MainWindow::Pause()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -150,6 +152,10 @@ void MainWindow::ProcessStory()
|
||||||
m_chip32_ctx.registers[R0] = 0x08;
|
m_chip32_ctx.registers[R0] = 0x08;
|
||||||
m_dbg.run_result = VM_OK;
|
m_dbg.run_result = VM_OK;
|
||||||
}
|
}
|
||||||
|
else if (event.type == VmEventType::EvStop)
|
||||||
|
{
|
||||||
|
m_dbg.run_result = VM_FINISHED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -704,6 +710,7 @@ void MainWindow::Loop()
|
||||||
|
|
||||||
while (!done)
|
while (!done)
|
||||||
{
|
{
|
||||||
|
auto time = SDL_GetTicks();
|
||||||
bool aboutToClose = m_gui.PollEvent();
|
bool aboutToClose = m_gui.PollEvent();
|
||||||
|
|
||||||
m_gui.StartFrame();
|
m_gui.StartFrame();
|
||||||
|
|
@ -746,6 +753,12 @@ void MainWindow::Loop()
|
||||||
|
|
||||||
m_gui.EndFrame();
|
m_gui.EndFrame();
|
||||||
|
|
||||||
|
|
||||||
|
// Rendering and event handling
|
||||||
|
if ((SDL_GetTicks() - time) < 10) {
|
||||||
|
SDL_Delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -799,18 +812,24 @@ void MainWindow::DeleteResource(FilterIterator &it)
|
||||||
return m_resources.Delete(it);
|
return m_resources.Delete(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Build()
|
void MainWindow::Build(bool compileonly)
|
||||||
{
|
{
|
||||||
// 1. First compile nodes to assembly
|
// 1. First compile nodes to assembly
|
||||||
CompileToAssembler();
|
if (CompileToAssembler())
|
||||||
|
{
|
||||||
|
|
||||||
// 2. Compile the assembly to machine binary
|
// 2. Compile the assembly to machine binary
|
||||||
GenerateBinary();
|
GenerateBinary();
|
||||||
|
|
||||||
// 3. Convert all media to desired type format
|
if (!compileonly)
|
||||||
ConvertResources();
|
{
|
||||||
|
// 3. Convert all media to desired type format
|
||||||
|
ConvertResources();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string MainWindow::GetNodeEntryLabel(const std::string &nodeId)
|
std::string MainWindow::GetNodeEntryLabel(const std::string &nodeId)
|
||||||
{
|
{
|
||||||
return m_nodeEditorWindow.GetNodeEntryLabel(nodeId);
|
return m_nodeEditorWindow.GetNodeEntryLabel(nodeId);
|
||||||
|
|
@ -827,9 +846,10 @@ bool MainWindow::CompileToAssembler()
|
||||||
// FIXME
|
// FIXME
|
||||||
|
|
||||||
// 2. Generate the assembly code from the model
|
// 2. Generate the assembly code from the model
|
||||||
m_currentCode = m_nodeEditorWindow.Build();
|
bool ret = m_nodeEditorWindow.Build(m_currentCode);
|
||||||
|
|
||||||
// Add global functions
|
// Add global functions
|
||||||
|
if (ret)
|
||||||
{
|
{
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
|
|
||||||
|
|
@ -839,11 +859,11 @@ bool MainWindow::CompileToAssembler()
|
||||||
f.seekg(0);
|
f.seekg(0);
|
||||||
f.read(buffer.data(), buffer.size());
|
f.read(buffer.data(), buffer.size());
|
||||||
m_currentCode += buffer;
|
m_currentCode += buffer;
|
||||||
|
|
||||||
|
m_editorWindow.SetScript(m_currentCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_editorWindow.SetScript(m_currentCode);
|
return ret;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::GenerateBinary()
|
void MainWindow::GenerateBinary()
|
||||||
|
|
@ -932,14 +952,19 @@ void MainWindow::ConvertResources()
|
||||||
int retCode = 0;
|
int retCode = 0;
|
||||||
if ((*it)->format == "PNG")
|
if ((*it)->format == "PNG")
|
||||||
{
|
{
|
||||||
outputfile += ".qoi"; // FIXME: prendre la congif en cours désirée
|
outputfile += ".qoi"; // FIXME: prendre la config en cours désirée
|
||||||
retCode = MediaConverter::ImageToQoi(inputfile, outputfile);
|
retCode = MediaConverter::ImageToQoi(inputfile, outputfile);
|
||||||
}
|
}
|
||||||
else if ((*it)->format == "MP3")
|
else if ((*it)->format == "MP3")
|
||||||
{
|
{
|
||||||
outputfile += ".wav"; // FIXME: prendre la congif en cours désirée
|
outputfile += ".wav"; // FIXME: prendre la config en cours désirée
|
||||||
retCode = MediaConverter::Mp3ToWav(inputfile, outputfile);
|
retCode = MediaConverter::Mp3ToWav(inputfile, outputfile);
|
||||||
}
|
}
|
||||||
|
else if ((*it)->format == "OGG")
|
||||||
|
{
|
||||||
|
outputfile += ".wav"; // FIXME: prendre la config en cours désirée
|
||||||
|
retCode = MediaConverter::OggToWav(inputfile, outputfile);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log("Skipped: " + inputfile + ", unknown format" + outputfile, true);
|
Log("Skipped: " + inputfile + ", unknown format" + outputfile, true);
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ public:
|
||||||
void Loop();
|
void Loop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished};
|
enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished, EvStop};
|
||||||
|
|
||||||
std::shared_ptr<StoryProject> m_story;
|
std::shared_ptr<StoryProject> m_story;
|
||||||
|
|
||||||
|
|
@ -134,11 +134,12 @@ private:
|
||||||
virtual void ClearResources() override;
|
virtual void ClearResources() override;
|
||||||
virtual std::pair<FilterIterator, FilterIterator> Resources() override;
|
virtual std::pair<FilterIterator, FilterIterator> Resources() override;
|
||||||
virtual void DeleteResource(FilterIterator &it) override;
|
virtual void DeleteResource(FilterIterator &it) override;
|
||||||
virtual void Build() override;
|
virtual void Build(bool compileonly) override;
|
||||||
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) override;
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) override;
|
||||||
virtual std::string GetNodeEntryLabel(const std::string &nodeId) override;
|
virtual std::string GetNodeEntryLabel(const std::string &nodeId) override;
|
||||||
virtual void Play() override;
|
virtual void Play() override;
|
||||||
virtual void Ok() override;
|
virtual void Ok() override;
|
||||||
|
virtual void Stop() override;
|
||||||
virtual void Pause() override;
|
virtual void Pause() override;
|
||||||
virtual void Next() override;
|
virtual void Next() override;
|
||||||
virtual void Previous() override;
|
virtual void Previous() override;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define STB_VORBIS_HEADER_ONLY
|
||||||
|
#include "stb_vorbis.c"
|
||||||
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
@ -158,6 +162,86 @@ int MediaConverter::Mp3ToWav(const std::string &inputFileName, const std::string
|
||||||
return cSuccess;
|
return cSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Function to read the entire contents of a file into memory
|
||||||
|
static unsigned char* read_entire_file(const char* filename, int* length) {
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
if (!f) return NULL;
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long size = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
unsigned char* buffer = (unsigned char*)malloc(size);
|
||||||
|
if (!buffer) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fread(buffer, 1, size, f);
|
||||||
|
fclose(f);
|
||||||
|
if (length) *length = (int)size;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MediaConverter::OggToWav(const std::string &inputFileName, const std::string &outputFileName)
|
||||||
|
{
|
||||||
|
|
||||||
|
int ogg_length;
|
||||||
|
unsigned char* ogg_data = read_entire_file(inputFileName.c_str(), &ogg_length);
|
||||||
|
if (!ogg_data) {
|
||||||
|
std::cout << "Failed to read input file " << inputFileName << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int channels, sample_rate;
|
||||||
|
short* samples = NULL;
|
||||||
|
// (const uint8 *mem, int len, int *channels, int *sample_rate, short **output
|
||||||
|
int data_len = stb_vorbis_decode_memory(ogg_data, ogg_length, &channels, &sample_rate, &samples);
|
||||||
|
if (!samples) {
|
||||||
|
std::cout <<"Failed to decode OGG file " << inputFileName << std::endl;
|
||||||
|
free(ogg_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write WAV file header
|
||||||
|
FILE* wav_file = fopen(outputFileName.c_str(), "wb");
|
||||||
|
if (!wav_file) {
|
||||||
|
std::cout << "Failed to create output file " << outputFileName << std::endl;
|
||||||
|
free(ogg_data);
|
||||||
|
free(samples);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fwrite("RIFF", 1, 4, wav_file);
|
||||||
|
int total_size = 36 + channels * (sample_rate * sizeof(short));
|
||||||
|
fwrite(&total_size, 4, 1, wav_file);
|
||||||
|
fwrite("WAVEfmt ", 1, 8, wav_file);
|
||||||
|
int format_size = 16;
|
||||||
|
fwrite(&format_size, 4, 1, wav_file);
|
||||||
|
short format_type = 1; // PCM
|
||||||
|
fwrite(&format_type, 2, 1, wav_file);
|
||||||
|
fwrite(&channels, 2, 1, wav_file);
|
||||||
|
fwrite(&sample_rate, 4, 1, wav_file);
|
||||||
|
int byte_rate = sample_rate * channels * sizeof(short);
|
||||||
|
fwrite(&byte_rate, 4, 1, wav_file);
|
||||||
|
short block_align = channels * sizeof(short);
|
||||||
|
fwrite(&block_align, 2, 1, wav_file);
|
||||||
|
short bits_per_sample = 16;
|
||||||
|
fwrite(&bits_per_sample, 2, 1, wav_file);
|
||||||
|
fwrite("data", 1, 4, wav_file);
|
||||||
|
// int data_size = channels * (sample_rate * sizeof(short));
|
||||||
|
|
||||||
|
int data_size = data_len * channels * 2; // *2 to make in bytes
|
||||||
|
fwrite(&data_size, 4, 1, wav_file);
|
||||||
|
|
||||||
|
// Write sample data
|
||||||
|
fwrite(samples, sizeof(short), data_len, wav_file);
|
||||||
|
|
||||||
|
fclose(wav_file);
|
||||||
|
|
||||||
|
free(ogg_data);
|
||||||
|
free(samples);
|
||||||
|
|
||||||
|
return cSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
OGG TO WAV
|
OGG TO WAV
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ public:
|
||||||
MediaConverter();
|
MediaConverter();
|
||||||
static int ImageToQoi(const std::string &inputFileName, const std::string &outputFileName);
|
static int ImageToQoi(const std::string &inputFileName, const std::string &outputFileName);
|
||||||
static int Mp3ToWav(const std::string &inputFileName, const std::string &outputFileName);
|
static int Mp3ToWav(const std::string &inputFileName, const std::string &outputFileName);
|
||||||
|
static int OggToWav(const std::string &inputFileName, const std::string &outputFileName);
|
||||||
private:
|
private:
|
||||||
static short *Mp3Read(const std::string &path, MediaInfo &desc);
|
static short *Mp3Read(const std::string &path, MediaInfo &desc);
|
||||||
static int WavWrite(const std::string &path, short *sample_data, MediaInfo &desc);
|
static int WavWrite(const std::string &path, short *sample_data, MediaInfo &desc);
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ std::string NodeEditorWindow::FindFirstNode() const
|
||||||
for (const auto & n : m_nodes)
|
for (const auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
bool foundConnection = false;
|
bool foundConnection = false;
|
||||||
|
|
||||||
for (const auto& l : m_links)
|
for (const auto& l : m_links)
|
||||||
{
|
{
|
||||||
if (l->model->inNodeId == n->GetId())
|
if (l->model->inNodeId == n->GetId())
|
||||||
|
|
@ -275,7 +276,7 @@ std::string NodeEditorWindow::FindFirstNode() const
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NodeEditorWindow::Build()
|
bool NodeEditorWindow::Build(std::string &codeStr)
|
||||||
{
|
{
|
||||||
std::stringstream code;
|
std::stringstream code;
|
||||||
ed::SetCurrentEditor(m_context);
|
ed::SetCurrentEditor(m_context);
|
||||||
|
|
@ -285,6 +286,12 @@ std::string NodeEditorWindow::Build()
|
||||||
|
|
||||||
std::string firstNode = FindFirstNode();
|
std::string firstNode = FindFirstNode();
|
||||||
|
|
||||||
|
if (firstNode == "")
|
||||||
|
{
|
||||||
|
m_story.Log("First node not found, there must be only one node with a free input.", true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
code << "\tjump " << GetNodeEntryLabel(firstNode) << "\r\n";
|
code << "\tjump " << GetNodeEntryLabel(firstNode) << "\r\n";
|
||||||
|
|
||||||
// First generate all constants
|
// First generate all constants
|
||||||
|
|
@ -299,7 +306,8 @@ std::string NodeEditorWindow::Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
ed::SetCurrentEditor(nullptr);
|
ed::SetCurrentEditor(nullptr);
|
||||||
return code.str();
|
codeStr = code.str();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(const std::string &nodeId)
|
std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(const std::string &nodeId)
|
||||||
|
|
@ -429,6 +437,18 @@ void NodeEditorWindow::Draw()
|
||||||
// Handle deletion action
|
// Handle deletion action
|
||||||
if (ed::BeginDelete())
|
if (ed::BeginDelete())
|
||||||
{
|
{
|
||||||
|
ed::NodeId nodeId = 0;
|
||||||
|
while (ed::QueryDeletedNode(&nodeId))
|
||||||
|
{
|
||||||
|
if (ed::AcceptDeletedItem())
|
||||||
|
{
|
||||||
|
auto id = std::find_if(m_nodes.begin(), m_nodes.end(), [nodeId](std::shared_ptr<BaseNodeWidget> node) { return node->GetInternalId() == nodeId.Get(); });
|
||||||
|
if (id != m_nodes.end())
|
||||||
|
m_nodes.erase(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// There may be many links marked for deletion, let's loop over them.
|
// There may be many links marked for deletion, let's loop over them.
|
||||||
ed::LinkId deletedLinkId;
|
ed::LinkId deletedLinkId;
|
||||||
while (ed::QueryDeletedLink(&deletedLinkId))
|
while (ed::QueryDeletedLink(&deletedLinkId))
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
void Load(const nlohmann::json &model);
|
void Load(const nlohmann::json &model);
|
||||||
void Save(nlohmann::json &model);
|
void Save(nlohmann::json &model);
|
||||||
std::string Build();
|
bool Build(std::string &codeStr);
|
||||||
std::list<std::shared_ptr<Connection> > GetNodeConnections(const std::string &nodeId);
|
std::list<std::shared_ptr<Connection> > GetNodeConnections(const std::string &nodeId);
|
||||||
std::string GetNodeEntryLabel(const std::string &nodeId);
|
std::string GetNodeEntryLabel(const std::string &nodeId);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue