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;
|
||||
|
||||
~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");
|
||||
|
||||
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();
|
||||
if (ImGui::Button("Build & Play"))
|
||||
if (ImGui::Button("Play"))
|
||||
{
|
||||
m_story.Log("Play story");
|
||||
m_story.Play();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Stop"))
|
||||
{
|
||||
m_story.Log("Stop story");
|
||||
m_story.Stop();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
WindowBase::EndDraw();
|
||||
|
|
|
|||
|
|
@ -45,11 +45,12 @@ public:
|
|||
virtual void DeleteResource(FilterIterator &it) = 0;
|
||||
|
||||
// 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::string GetNodeEntryLabel(const std::string &nodeId) = 0;
|
||||
virtual void Play() = 0;
|
||||
virtual void Ok() = 0;
|
||||
virtual void Stop() = 0;
|
||||
virtual void Pause() = 0;
|
||||
virtual void Next() = 0;
|
||||
virtual void Previous() = 0;
|
||||
|
|
|
|||
|
|
@ -66,16 +66,13 @@ std::string MainWindow::GetFileNameFromMemory(uint32_t addr)
|
|||
|
||||
void MainWindow::Play()
|
||||
{
|
||||
if (m_dbg.run_result == VM_FINISHED)
|
||||
{
|
||||
Build();
|
||||
|
||||
if (m_dbg.run_result == VM_READY)
|
||||
{
|
||||
m_dbg.free_run = true;
|
||||
m_dbg.run_result = VM_OK; // actually starts the execution
|
||||
}
|
||||
if ((m_dbg.run_result == VM_READY) || (m_dbg.run_result == VM_FINISHED))
|
||||
{
|
||||
m_dbg.free_run = true;
|
||||
m_dbg.run_result = VM_OK; // actually starts the execution
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::Ok()
|
||||
|
|
@ -83,6 +80,11 @@ void MainWindow::Ok()
|
|||
m_eventQueue.push({VmEventType::EvOkButton});
|
||||
}
|
||||
|
||||
void MainWindow::Stop()
|
||||
{
|
||||
m_eventQueue.push({VmEventType::EvOkButton});
|
||||
}
|
||||
|
||||
void MainWindow::Pause()
|
||||
{
|
||||
|
||||
|
|
@ -150,6 +152,10 @@ void MainWindow::ProcessStory()
|
|||
m_chip32_ctx.registers[R0] = 0x08;
|
||||
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)
|
||||
{
|
||||
auto time = SDL_GetTicks();
|
||||
bool aboutToClose = m_gui.PollEvent();
|
||||
|
||||
m_gui.StartFrame();
|
||||
|
|
@ -746,6 +753,12 @@ void MainWindow::Loop()
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
void MainWindow::Build()
|
||||
void MainWindow::Build(bool compileonly)
|
||||
{
|
||||
// 1. First compile nodes to assembly
|
||||
CompileToAssembler();
|
||||
if (CompileToAssembler())
|
||||
{
|
||||
|
||||
// 2. Compile the assembly to machine binary
|
||||
GenerateBinary();
|
||||
// 2. Compile the assembly to machine binary
|
||||
GenerateBinary();
|
||||
|
||||
// 3. Convert all media to desired type format
|
||||
ConvertResources();
|
||||
if (!compileonly)
|
||||
{
|
||||
// 3. Convert all media to desired type format
|
||||
ConvertResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string MainWindow::GetNodeEntryLabel(const std::string &nodeId)
|
||||
{
|
||||
return m_nodeEditorWindow.GetNodeEntryLabel(nodeId);
|
||||
|
|
@ -827,9 +846,10 @@ bool MainWindow::CompileToAssembler()
|
|||
// FIXME
|
||||
|
||||
// 2. Generate the assembly code from the model
|
||||
m_currentCode = m_nodeEditorWindow.Build();
|
||||
bool ret = m_nodeEditorWindow.Build(m_currentCode);
|
||||
|
||||
// Add global functions
|
||||
if (ret)
|
||||
{
|
||||
std::string buffer;
|
||||
|
||||
|
|
@ -839,11 +859,11 @@ bool MainWindow::CompileToAssembler()
|
|||
f.seekg(0);
|
||||
f.read(buffer.data(), buffer.size());
|
||||
m_currentCode += buffer;
|
||||
|
||||
m_editorWindow.SetScript(m_currentCode);
|
||||
}
|
||||
|
||||
m_editorWindow.SetScript(m_currentCode);
|
||||
|
||||
return true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MainWindow::GenerateBinary()
|
||||
|
|
@ -932,14 +952,19 @@ void MainWindow::ConvertResources()
|
|||
int retCode = 0;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
else if ((*it)->format == "OGG")
|
||||
{
|
||||
outputfile += ".wav"; // FIXME: prendre la config en cours désirée
|
||||
retCode = MediaConverter::OggToWav(inputfile, outputfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Skipped: " + inputfile + ", unknown format" + outputfile, true);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public:
|
|||
void Loop();
|
||||
|
||||
private:
|
||||
enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished};
|
||||
enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished, EvStop};
|
||||
|
||||
std::shared_ptr<StoryProject> m_story;
|
||||
|
||||
|
|
@ -134,11 +134,12 @@ private:
|
|||
virtual void ClearResources() override;
|
||||
virtual std::pair<FilterIterator, FilterIterator> Resources() 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::string GetNodeEntryLabel(const std::string &nodeId) override;
|
||||
virtual void Play() override;
|
||||
virtual void Ok() override;
|
||||
virtual void Stop() override;
|
||||
virtual void Pause() override;
|
||||
virtual void Next() override;
|
||||
virtual void Previous() override;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include "stb_vorbis.c"
|
||||
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
|
|
@ -158,6 +162,86 @@ int MediaConverter::Mp3ToWav(const std::string &inputFileName, const std::string
|
|||
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
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public:
|
|||
MediaConverter();
|
||||
static int ImageToQoi(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:
|
||||
static short *Mp3Read(const std::string &path, 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)
|
||||
{
|
||||
bool foundConnection = false;
|
||||
|
||||
for (const auto& l : m_links)
|
||||
{
|
||||
if (l->model->inNodeId == n->GetId())
|
||||
|
|
@ -275,7 +276,7 @@ std::string NodeEditorWindow::FindFirstNode() const
|
|||
return id;
|
||||
}
|
||||
|
||||
std::string NodeEditorWindow::Build()
|
||||
bool NodeEditorWindow::Build(std::string &codeStr)
|
||||
{
|
||||
std::stringstream code;
|
||||
ed::SetCurrentEditor(m_context);
|
||||
|
|
@ -285,6 +286,12 @@ std::string NodeEditorWindow::Build()
|
|||
|
||||
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";
|
||||
|
||||
// First generate all constants
|
||||
|
|
@ -299,7 +306,8 @@ std::string NodeEditorWindow::Build()
|
|||
}
|
||||
|
||||
ed::SetCurrentEditor(nullptr);
|
||||
return code.str();
|
||||
codeStr = code.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(const std::string &nodeId)
|
||||
|
|
@ -429,6 +437,18 @@ void NodeEditorWindow::Draw()
|
|||
// Handle deletion action
|
||||
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.
|
||||
ed::LinkId deletedLinkId;
|
||||
while (ed::QueryDeletedLink(&deletedLinkId))
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
void Clear();
|
||||
void Load(const 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::string GetNodeEntryLabel(const std::string &nodeId);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue