mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
editor: add about box, add mp3 converter, one asset for all media
This commit is contained in:
parent
d10afb0232
commit
620f06bf6c
19 changed files with 8718 additions and 88 deletions
|
|
@ -58,12 +58,16 @@ set(PROJECT_SOURCES
|
||||||
src/event_node_model.cpp
|
src/event_node_model.cpp
|
||||||
src/highlighter.h
|
src/highlighter.h
|
||||||
src/highlighter.cpp
|
src/highlighter.cpp
|
||||||
|
src/dr_mp3.h
|
||||||
|
src/media_converter.h
|
||||||
|
src/media_converter.cpp
|
||||||
src/ost-hmi.ui
|
src/ost-hmi.ui
|
||||||
src/ost-vm.ui
|
src/ost-vm.ui
|
||||||
src/ost-data.ui
|
src/ost-data.ui
|
||||||
src/ost-script.ui
|
src/ost-script.ui
|
||||||
src/ost-resources.ui
|
src/ost-resources.ui
|
||||||
src/ost-log.ui
|
src/ost-log.ui
|
||||||
|
src/about.ui
|
||||||
src/media-node.ui
|
src/media-node.ui
|
||||||
src/event-node.ui
|
src/event-node.ui
|
||||||
src/choose-file.ui
|
src/choose-file.ui
|
||||||
|
|
@ -71,6 +75,7 @@ set(PROJECT_SOURCES
|
||||||
../software/chip32/chip32_assembler.cpp
|
../software/chip32/chip32_assembler.cpp
|
||||||
../software/chip32/chip32_vm.c
|
../software/chip32/chip32_vm.c
|
||||||
../software/library/miniaudio.c
|
../software/library/miniaudio.c
|
||||||
|
../software/library/miniaudio.h
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(../software/chip32)
|
include_directories(../software/chip32)
|
||||||
|
|
|
||||||
199
story-editor/src/about.ui
Normal file
199
story-editor/src/about.ui
Normal file
|
|
@ -0,0 +1,199 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>aboutDialog</class>
|
||||||
|
<widget class="QDialog" name="aboutDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::WindowModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>452</width>
|
||||||
|
<height>321</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<property name="sizeGripEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>98</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>98</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="ost-editor.qrc">:/art/logo-color2.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>OpenStoryTeller</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="versionLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>vX.XX</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string><a href="http://openstoryteller.org/">http://openstoryteller.org</a></string>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><a href="http://github.com/arabine/open-story-teller/"><span style=" text-decoration: underline; color:#8ab4f8;">http://github.com/arabine/open-story-teller</span></a></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QTextBrowser" name="textBrowser">
|
||||||
|
<property name="html">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
hr { height: 1px; border-width: 0; }
|
||||||
|
li.unchecked::marker { content: "\2610"; }
|
||||||
|
li.checked::marker { content: "\2612"; }
|
||||||
|
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">MIT License</p>
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2023 Anthony Rabine</p>
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permission is hereby granted, free of charge, to any person obtaining a copy</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of this software and associated documentation files (the &quot;Software&quot;), to deal</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in the Software without restriction, including without limitation the rights</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to use, copy, modify, merge, publish, distribute, sublicense, and/or sell</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">copies of the Software, and to permit persons to whom the Software is</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">furnished to do so, subject to the following conditions:</p>
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above copyright notice and this permission notice shall be included in all</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">copies or substantial portions of the Software.</p>
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</p>
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">SOFTWARE.</p>
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="ost-editor.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>aboutDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>aboutDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
4831
story-editor/src/dr_mp3.h
Normal file
4831
story-editor/src/dr_mp3.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -37,16 +37,7 @@
|
||||||
|
|
||||||
#include "main_window.h"
|
#include "main_window.h"
|
||||||
#include "media_node_model.h"
|
#include "media_node_model.h"
|
||||||
|
#include "media_converter.h"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#define STBI_ONLY_PNG
|
|
||||||
#define STBI_NO_LINEAR
|
|
||||||
#include "stb_image.h"
|
|
||||||
|
|
||||||
#define QOI_IMPLEMENTATION
|
|
||||||
#undef QOI_NO_STDIO
|
|
||||||
#include "qoi.h"
|
|
||||||
|
|
||||||
using QtNodes::CreateCommand;
|
using QtNodes::CreateCommand;
|
||||||
using QtNodes::BasicGraphicsScene;
|
using QtNodes::BasicGraphicsScene;
|
||||||
|
|
@ -150,7 +141,7 @@ MainWindow::MainWindow()
|
||||||
|
|
||||||
readSettings(); // restore all windows preferences
|
readSettings(); // restore all windows preferences
|
||||||
qDebug() << "Settings location: " << m_settings.fileName();
|
qDebug() << "Settings location: " << m_settings.fileName();
|
||||||
qDebug() << "Welcome to StoryTeller Editor";
|
qDebug() << "Welcome to StoryTeller Editor " << OST_EDITOR_VERSION;
|
||||||
|
|
||||||
CloseProject();
|
CloseProject();
|
||||||
RefreshProjectInformation();
|
RefreshProjectInformation();
|
||||||
|
|
@ -338,49 +329,32 @@ void MainWindow::ConvertResources()
|
||||||
std::vector<Resource>::const_iterator ptr = m_project.Begin();
|
std::vector<Resource>::const_iterator ptr = m_project.Begin();
|
||||||
for (; ptr != m_project.End(); ++ptr)
|
for (; ptr != m_project.End(); ++ptr)
|
||||||
{
|
{
|
||||||
|
QString inputfile = m_model.BuildFullAssetsPath(ptr->file.c_str());
|
||||||
|
std::string outputfile = m_project.AssetsPath() / StoryProject::RemoveFileExtension(ptr->file);
|
||||||
|
|
||||||
|
int retCode = 0;
|
||||||
if (ptr->format == "PNG")
|
if (ptr->format == "PNG")
|
||||||
{
|
{
|
||||||
QString inputfile = m_model.BuildFullImagePath(ptr->file.c_str());
|
outputfile += ".qoi"; // FIXME: prendre la congif en cours désirée
|
||||||
void *pixels = NULL;
|
retCode = MediaConverter::ImageToQoi(inputfile.toStdString(), outputfile);
|
||||||
int w = 0;
|
}
|
||||||
int h = 0;
|
else if (ptr->format == "MP3")
|
||||||
int channels = 0;
|
{
|
||||||
|
outputfile += ".wav"; // FIXME: prendre la congif en cours désirée
|
||||||
|
retCode = MediaConverter::Mp3ToWav(inputfile.toStdString(), outputfile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCritical() << "Skipped: " << inputfile << ", unknown format" << outputfile;
|
||||||
|
}
|
||||||
|
|
||||||
if(!stbi_info(inputfile.toStdString().c_str(), &w, &h, &channels))
|
if (retCode < 0)
|
||||||
{
|
{
|
||||||
qCritical() << "Couldn't read header " << inputfile;
|
qCritical() << "Failed to convert media file " << inputfile << ", error code: " << retCode << outputfile;
|
||||||
}
|
}
|
||||||
|
else if (retCode == 0)
|
||||||
// Force all odd encodings to be RGBA
|
{
|
||||||
if(channels != 3) {
|
qDebug() << "Convertered file: " << inputfile;
|
||||||
channels = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixels = (void *)stbi_load(inputfile.toStdString().c_str(), &w, &h, NULL, channels);
|
|
||||||
|
|
||||||
if (pixels != NULL)
|
|
||||||
{
|
|
||||||
qoi_desc desc;
|
|
||||||
desc.channels = channels;
|
|
||||||
desc.colorspace = QOI_SRGB;
|
|
||||||
desc.width = w;
|
|
||||||
desc.height = h;
|
|
||||||
|
|
||||||
std::string outputfile = m_project.ImagesPath() / StoryProject::RemoveFileExtension(ptr->file);
|
|
||||||
outputfile += ".qoi";
|
|
||||||
int encoded = qoi_write(outputfile.c_str(), pixels, &desc);
|
|
||||||
|
|
||||||
if (!encoded)
|
|
||||||
{
|
|
||||||
qCritical() << "Couldn't write/encode " << outputfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(pixels);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCritical() << "Couldn't load/decode" << inputfile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -449,7 +423,7 @@ void MainWindow::ExitProgram()
|
||||||
|
|
||||||
void MainWindow::RefreshProjectInformation()
|
void MainWindow::RefreshProjectInformation()
|
||||||
{
|
{
|
||||||
setWindowTitle(QString("StoryTeller Editor - ") + m_project.GetProjectFilePath().c_str());
|
setWindowTitle(QString("StoryTeller Editor %1 - %2").arg(OST_EDITOR_VERSION).arg(m_project.GetProjectFilePath().c_str()));
|
||||||
|
|
||||||
m_resourcesDock->SetTitleImage(m_project.GetTitleImage().c_str());
|
m_resourcesDock->SetTitleImage(m_project.GetTitleImage().c_str());
|
||||||
m_resourcesDock->SetTitleSound(m_project.GetTitleSound().c_str());
|
m_resourcesDock->SetTitleSound(m_project.GetTitleSound().c_str());
|
||||||
|
|
@ -658,7 +632,7 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
if (m_chip32_ctx.registers[R0] != 0)
|
if (m_chip32_ctx.registers[R0] != 0)
|
||||||
{
|
{
|
||||||
// image file name address is in R0
|
// image file name address is in R0
|
||||||
QString imageFile = m_model.BuildFullImagePath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
QString imageFile = m_model.BuildFullAssetsPath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
||||||
qDebug() << "Image: " << imageFile;
|
qDebug() << "Image: " << imageFile;
|
||||||
m_ostHmiDock->SetImage(imageFile);
|
m_ostHmiDock->SetImage(imageFile);
|
||||||
}
|
}
|
||||||
|
|
@ -670,7 +644,7 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
if (m_chip32_ctx.registers[R1] != 0)
|
if (m_chip32_ctx.registers[R1] != 0)
|
||||||
{
|
{
|
||||||
// sound file name address is in R1
|
// sound file name address is in R1
|
||||||
QString soundFile = m_model.BuildFullSoundPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
QString soundFile = m_model.BuildFullAssetsPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
||||||
qDebug() << ", Sound: " << soundFile;
|
qDebug() << ", Sound: " << soundFile;
|
||||||
m_model.PlaySoundFile(soundFile);
|
m_model.PlaySoundFile(soundFile);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
160
story-editor/src/media_converter.cpp
Normal file
160
story-editor/src/media_converter.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
#include "media_converter.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STBI_ONLY_PNG
|
||||||
|
#define STBI_NO_LINEAR
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
#define QOI_IMPLEMENTATION
|
||||||
|
#undef QOI_NO_STDIO
|
||||||
|
#include "qoi.h"
|
||||||
|
|
||||||
|
//#define DR_MP3_IMPLEMENTATION
|
||||||
|
#include "dr_mp3.h"
|
||||||
|
|
||||||
|
MediaConverter::MediaConverter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MediaConverter::ImageToQoi(const std::string &inputFileName, const std::string &outputFileName)
|
||||||
|
{
|
||||||
|
void *pixels = NULL;
|
||||||
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
|
int channels = 0;
|
||||||
|
|
||||||
|
if(!stbi_info(inputFileName.c_str(), &w, &h, &channels))
|
||||||
|
{
|
||||||
|
return cErrorBadInputFileFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force all odd encodings to be RGBA
|
||||||
|
if(channels != 3) {
|
||||||
|
channels = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels = (void *)stbi_load(inputFileName.c_str(), &w, &h, NULL, channels);
|
||||||
|
|
||||||
|
if (pixels != NULL)
|
||||||
|
{
|
||||||
|
qoi_desc desc;
|
||||||
|
desc.channels = channels;
|
||||||
|
desc.colorspace = QOI_SRGB;
|
||||||
|
desc.width = w;
|
||||||
|
desc.height = h;
|
||||||
|
|
||||||
|
int encoded = qoi_write(outputFileName.c_str(), pixels, &desc);
|
||||||
|
free(pixels);
|
||||||
|
|
||||||
|
if (!encoded)
|
||||||
|
{
|
||||||
|
return cErrorCannotWriteOrEncodeOutputFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return cErrorCannotDecodeInputFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwrite_u32_le(unsigned int v, FILE *fh) {
|
||||||
|
unsigned char buf[sizeof(unsigned int)];
|
||||||
|
buf[0] = 0xff & (v );
|
||||||
|
buf[1] = 0xff & (v >> 8);
|
||||||
|
buf[2] = 0xff & (v >> 16);
|
||||||
|
buf[3] = 0xff & (v >> 24);
|
||||||
|
int wrote = fwrite(buf, sizeof(unsigned int), 1, fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwrite_u16_le(unsigned short v, FILE *fh) {
|
||||||
|
unsigned char buf[sizeof(unsigned short)];
|
||||||
|
buf[0] = 0xff & (v );
|
||||||
|
buf[1] = 0xff & (v >> 8);
|
||||||
|
int wrote = fwrite(buf, sizeof(unsigned short), 1, fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MediaConverter::WavWrite(const std::string &path, short *sample_data, MediaInfo &desc)
|
||||||
|
{
|
||||||
|
unsigned int data_size = desc.samples * desc.channels * sizeof(short);
|
||||||
|
unsigned int samplerate = desc.samplerate;
|
||||||
|
short bits_per_sample = 16;
|
||||||
|
short channels = desc.channels;
|
||||||
|
|
||||||
|
/* Lifted from https://www.jonolick.com/code.html - public domain
|
||||||
|
Made endian agnostic using qoaconv_fwrite() */
|
||||||
|
FILE *fh = fopen(path.c_str(), "wb");
|
||||||
|
|
||||||
|
if (fh != NULL)
|
||||||
|
{
|
||||||
|
fwrite("RIFF", 1, 4, fh);
|
||||||
|
fwrite_u32_le(data_size + 44 - 8, fh);
|
||||||
|
fwrite("WAVEfmt \x10\x00\x00\x00\x01\x00", 1, 14, fh);
|
||||||
|
fwrite_u16_le(channels, fh);
|
||||||
|
fwrite_u32_le(samplerate, fh);
|
||||||
|
fwrite_u32_le(channels * samplerate * bits_per_sample/8, fh);
|
||||||
|
fwrite_u16_le(channels * bits_per_sample/8, fh);
|
||||||
|
fwrite_u16_le(bits_per_sample, fh);
|
||||||
|
fwrite("data", 1, 4, fh);
|
||||||
|
fwrite_u32_le(data_size, fh);
|
||||||
|
fwrite((void*)sample_data, data_size, 1, fh);
|
||||||
|
fclose(fh);
|
||||||
|
return data_size + 44 - 8;
|
||||||
|
}
|
||||||
|
return cErrorCannotWriteOrEncodeOutputFile;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
short *MediaConverter::Mp3Read(const std::string &path, MediaInfo &desc)
|
||||||
|
{
|
||||||
|
drmp3_uint64 samples = 0;
|
||||||
|
|
||||||
|
drmp3_config mp3 = {
|
||||||
|
.channels = 2,
|
||||||
|
.sampleRate = 44100
|
||||||
|
};
|
||||||
|
short* sample_data = drmp3_open_file_and_read_pcm_frames_s16(path.c_str(), &mp3, &samples, NULL);
|
||||||
|
|
||||||
|
desc.samplerate = mp3.sampleRate;
|
||||||
|
desc.channels = mp3.channels;
|
||||||
|
desc.samples = samples;
|
||||||
|
|
||||||
|
return sample_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MediaConverter::Mp3ToWav(const std::string &inputFileName, const std::string &outputFileName)
|
||||||
|
{
|
||||||
|
MediaInfo media;
|
||||||
|
short *sample_data = NULL;
|
||||||
|
|
||||||
|
sample_data = Mp3Read(inputFileName, media);
|
||||||
|
|
||||||
|
if (sample_data != NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
int bytes_written = WavWrite(outputFileName, sample_data, media);
|
||||||
|
|
||||||
|
free(sample_data);
|
||||||
|
|
||||||
|
if (bytes_written < 0)
|
||||||
|
{
|
||||||
|
return bytes_written; // error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return cErrorBadInputFileFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cSuccess;
|
||||||
|
}
|
||||||
29
story-editor/src/media_converter.h
Normal file
29
story-editor/src/media_converter.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef MEDIA_CONVERTER_H
|
||||||
|
#define MEDIA_CONVERTER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class MediaConverter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int cSuccess = 0;
|
||||||
|
static const int cErrorBadInputFileFormat = -1;
|
||||||
|
static const int cErrorCannotDecodeInputFile = -2;
|
||||||
|
static const int cErrorCannotWriteOrEncodeOutputFile = -3;
|
||||||
|
|
||||||
|
|
||||||
|
struct MediaInfo {
|
||||||
|
uint32_t samplerate;
|
||||||
|
uint32_t channels;
|
||||||
|
uint64_t samples;
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaConverter();
|
||||||
|
static int ImageToQoi(const std::string &inputFileName, const std::string &outputFileName);
|
||||||
|
static int Mp3ToWav(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);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MEDIA_CONVERTER_H
|
||||||
|
|
@ -109,7 +109,7 @@ void MediaNodeModel::FromJson(nlohmann::json &j)
|
||||||
|
|
||||||
void MediaNodeModel::setImage(const QString &fileName)
|
void MediaNodeModel::setImage(const QString &fileName)
|
||||||
{
|
{
|
||||||
QPixmap pix(m_model.BuildFullImagePath(fileName));
|
QPixmap pix(m_model.BuildFullAssetsPath(fileName));
|
||||||
|
|
||||||
if (!pix.isNull())
|
if (!pix.isNull())
|
||||||
{
|
{
|
||||||
|
|
@ -129,7 +129,7 @@ void MediaNodeModel::setInternalData(const nlohmann::json &j)
|
||||||
|
|
||||||
if (j.contains("sound")) {
|
if (j.contains("sound")) {
|
||||||
QString fileName = j["sound"].get<std::string>().c_str();
|
QString fileName = j["sound"].get<std::string>().c_str();
|
||||||
m_soundFilePath = m_model.BuildFullSoundPath(fileName);
|
m_soundFilePath = m_model.BuildFullAssetsPath(fileName);
|
||||||
m_ui.soundName->setText(fileName);
|
m_ui.soundName->setText(fileName);
|
||||||
m_ui.playSoundButton->setEnabled(true);
|
m_ui.playSoundButton->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,6 @@
|
||||||
<file>../assets/pause-button.png</file>
|
<file>../assets/pause-button.png</file>
|
||||||
<file>../assets/right.png</file>
|
<file>../assets/right.png</file>
|
||||||
<file>../assets/check-mark.png</file>
|
<file>../assets/check-mark.png</file>
|
||||||
|
<file>../../art/logo-color2.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
||||||
if (std::filesystem::exists(fileName.toStdString()))
|
if (std::filesystem::exists(fileName.toStdString()))
|
||||||
{
|
{
|
||||||
std::filesystem::path p(fileName.toStdString());
|
std::filesystem::path p(fileName.toStdString());
|
||||||
std::filesystem::path p2 = m_project.ImagesPath() / p.filename().generic_string();
|
std::filesystem::path p2 = m_project.AssetsPath() / p.filename().generic_string();
|
||||||
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
|
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
|
||||||
|
|
||||||
Resource res;
|
Resource res;
|
||||||
|
|
@ -48,7 +48,7 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
||||||
if (std::filesystem::exists(fileName.toStdString()))
|
if (std::filesystem::exists(fileName.toStdString()))
|
||||||
{
|
{
|
||||||
std::filesystem::path p(fileName.toStdString());
|
std::filesystem::path p(fileName.toStdString());
|
||||||
std::filesystem::path p2 = m_project.SoundsPath() / p.filename().generic_string();
|
std::filesystem::path p2 = m_project.AssetsPath() / p.filename().generic_string();
|
||||||
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
|
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
|
||||||
|
|
||||||
Resource res;
|
Resource res;
|
||||||
|
|
|
||||||
|
|
@ -583,24 +583,14 @@ void StoryGraphModel::removePort(NodeId nodeId, PortType portType, PortIndex por
|
||||||
portsDeleted();
|
portsDeleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString StoryGraphModel::GetImagesDir() const
|
QString StoryGraphModel::GetAssetsDir() const
|
||||||
{
|
{
|
||||||
return QString(m_project.GetWorkingDir().c_str()) + QDir::separator() + "images";
|
return QString(m_project.GetWorkingDir().c_str()) + QDir::separator() + "assets";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString StoryGraphModel::BuildFullImagePath(const QString &fileName) const
|
QString StoryGraphModel::BuildFullAssetsPath(const QString &fileName) const
|
||||||
{
|
{
|
||||||
return GetImagesDir() + QDir::separator() + fileName;
|
return GetAssetsDir() + QDir::separator() + fileName;
|
||||||
}
|
|
||||||
|
|
||||||
QString StoryGraphModel::GetSoundsDir() const
|
|
||||||
{
|
|
||||||
return QString(m_project.GetWorkingDir().c_str()) + QDir::separator() + "sounds";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString StoryGraphModel::BuildFullSoundPath(const QString &fileName) const
|
|
||||||
{
|
|
||||||
return GetSoundsDir() + QDir::separator() + fileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StoryGraphModel::Clear()
|
void StoryGraphModel::Clear()
|
||||||
|
|
|
||||||
|
|
@ -161,10 +161,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
StoryProject &GetProject() { return m_project; };
|
StoryProject &GetProject() { return m_project; };
|
||||||
QString GetImagesDir() const;
|
QString GetAssetsDir() const;
|
||||||
QString GetSoundsDir() const;
|
QString BuildFullAssetsPath(const QString &fileName) const;
|
||||||
QString BuildFullImagePath(const QString &fileName) const;
|
|
||||||
QString BuildFullSoundPath(const QString &fileName) const;
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void SetInternalData(NodeId nodeId, nlohmann::json &j);
|
void SetInternalData(NodeId nodeId, nlohmann::json &j);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,11 +92,9 @@ void StoryProject::Initialize(const std::string &file_path)
|
||||||
{
|
{
|
||||||
std::filesystem::create_directories(m_working_dir);
|
std::filesystem::create_directories(m_working_dir);
|
||||||
}
|
}
|
||||||
m_imagesPath = std::filesystem::path(m_working_dir) / "images";
|
m_assetsPath = std::filesystem::path(m_working_dir) / "assets";
|
||||||
m_soundsPath = std::filesystem::path(m_working_dir) / "sounds";
|
|
||||||
|
|
||||||
std::filesystem::create_directories(m_imagesPath);
|
std::filesystem::create_directories(m_assetsPath);
|
||||||
std::filesystem::create_directories(m_soundsPath);
|
|
||||||
|
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,7 @@ struct StoryProject
|
||||||
std::string GetName() const { return m_name; }
|
std::string GetName() const { return m_name; }
|
||||||
std::string GetUuid() const { return m_uuid; }
|
std::string GetUuid() const { return m_uuid; }
|
||||||
|
|
||||||
std::filesystem::path ImagesPath() const { return m_imagesPath; }
|
std::filesystem::path AssetsPath() const { return m_assetsPath; }
|
||||||
std::filesystem::path SoundsPath() const { return m_soundsPath; }
|
|
||||||
|
|
||||||
static std::string GetFileExtension(const std::string &FileName);
|
static std::string GetFileExtension(const std::string &FileName);
|
||||||
static std::string GetFileName(const std::string &path);
|
static std::string GetFileName(const std::string &path);
|
||||||
|
|
@ -119,8 +118,8 @@ private:
|
||||||
// Project properties and location
|
// Project properties and location
|
||||||
std::string m_name; /// human readable name
|
std::string m_name; /// human readable name
|
||||||
std::string m_uuid;
|
std::string m_uuid;
|
||||||
std::filesystem::path m_imagesPath;
|
std::filesystem::path m_assetsPath;
|
||||||
std::filesystem::path m_soundsPath;
|
|
||||||
bool m_initialized{false};
|
bool m_initialized{false};
|
||||||
|
|
||||||
std::string m_titleImage;
|
std::string m_titleImage;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ ToolBar::ToolBar()
|
||||||
{
|
{
|
||||||
setObjectName("MainToolBar");
|
setObjectName("MainToolBar");
|
||||||
|
|
||||||
|
m_aboutDialog = new QDialog();
|
||||||
|
m_aboutUi.setupUi(m_aboutDialog);
|
||||||
|
|
||||||
|
m_aboutUi.versionLabel->setText(OST_EDITOR_VERSION);
|
||||||
// setIconSize(QSize(10, 10));
|
// setIconSize(QSize(10, 10));
|
||||||
// setFixedHeight(36);
|
// setFixedHeight(36);
|
||||||
}
|
}
|
||||||
|
|
@ -151,9 +155,7 @@ void ToolBar::SetActionsActive(bool enable)
|
||||||
|
|
||||||
void ToolBar::slotAbout()
|
void ToolBar::slotAbout()
|
||||||
{
|
{
|
||||||
QMessageBox::about(this, tr("About OST Editor"),
|
m_aboutDialog->exec();
|
||||||
tr("OpenStoryTeller node editor."
|
|
||||||
"Build your own stories on an open source hardware."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolBar::AddDockToMenu(QAction *action, DockWidgetBase *dock)
|
void ToolBar::AddDockToMenu(QAction *action, DockWidgetBase *dock)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include "dock_widget_base.h"
|
#include "dock_widget_base.h"
|
||||||
|
#include "ui_about.h"
|
||||||
|
|
||||||
|
#define OST_EDITOR_VERSION "0.1.0"
|
||||||
|
|
||||||
class ToolBar : public QToolBar
|
class ToolBar : public QToolBar
|
||||||
{
|
{
|
||||||
|
|
@ -39,6 +42,8 @@ private:
|
||||||
QAction *m_runAction{nullptr};
|
QAction *m_runAction{nullptr};
|
||||||
QList<QAction *> m_actionDockList;
|
QList<QAction *> m_actionDockList;
|
||||||
QList<DockWidgetBase *> m_docksList;
|
QList<DockWidgetBase *> m_docksList;
|
||||||
|
Ui::aboutDialog m_aboutUi;
|
||||||
|
QDialog *m_aboutDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TOOLBAR_H
|
#endif // TOOLBAR_H
|
||||||
|
|
|
||||||
117
story-editor/tools/audio/LICENSE
Normal file
117
story-editor/tools/audio/LICENSE
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
|
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||||
|
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
|
authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||||
|
purpose of contributing to a commons of creative, cultural and scientific
|
||||||
|
works ("Commons") that the public can reliably and without fear of later
|
||||||
|
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||||
|
and redistribute as freely as possible in any form whatsoever and for any
|
||||||
|
purposes, including without limitation commercial purposes. These owners may
|
||||||
|
contribute to the Commons to promote the ideal of a free culture and the
|
||||||
|
further production of creative, cultural and scientific works, or to gain
|
||||||
|
reputation or greater distribution for their Work in part through the use and
|
||||||
|
efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any expectation
|
||||||
|
of additional consideration or compensation, the person associating CC0 with a
|
||||||
|
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||||
|
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||||
|
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||||
|
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||||
|
effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
|
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||||
|
to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||||
|
and translate a Work;
|
||||||
|
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||||
|
depicted in a Work;
|
||||||
|
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
|
subject to the limitations in paragraph 4(a), below;
|
||||||
|
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||||
|
a Work;
|
||||||
|
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation thereof,
|
||||||
|
including any amended or successor version of such directive); and
|
||||||
|
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the world
|
||||||
|
based on applicable law or treaty, and any national implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||||
|
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||||
|
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||||
|
and Related Rights and associated claims and causes of action, whether now
|
||||||
|
known or unknown (including existing as well as future claims and causes of
|
||||||
|
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||||
|
duration provided by applicable law or treaty (including future time
|
||||||
|
extensions), (iii) in any current or future medium and for any number of
|
||||||
|
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||||
|
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||||
|
the Waiver for the benefit of each member of the public at large and to the
|
||||||
|
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||||
|
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||||
|
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||||
|
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||||
|
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||||
|
shall be preserved to the maximum extent permitted taking into account
|
||||||
|
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||||
|
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||||
|
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||||
|
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||||
|
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||||
|
provided by applicable law or treaty (including future time extensions), (iii)
|
||||||
|
in any current or future medium and for any number of copies, and (iv) for any
|
||||||
|
purpose whatsoever, including without limitation commercial, advertising or
|
||||||
|
promotional purposes (the "License"). The License shall be deemed effective as
|
||||||
|
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||||
|
License for any reason be judged legally invalid or ineffective under
|
||||||
|
applicable law, such partial invalidity or ineffectiveness shall not
|
||||||
|
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||||
|
affirms that he or she will not (i) exercise any of his or her remaining
|
||||||
|
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||||
|
and causes of action with respect to the Work, in either case contrary to
|
||||||
|
Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
|
surrendered, licensed or otherwise affected by this document.
|
||||||
|
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||||
|
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||||
|
including without limitation warranties of title, merchantability, fitness
|
||||||
|
for a particular purpose, non infringement, or the absence of latent or
|
||||||
|
other defects, accuracy, or the present or absence of errors, whether or not
|
||||||
|
discoverable, all to the greatest extent permissible under applicable law.
|
||||||
|
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without limitation
|
||||||
|
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||||
|
disclaims responsibility for obtaining any necessary consents, permissions
|
||||||
|
or other rights required for any use of the Work.
|
||||||
|
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
|
party to this document and has no duty or obligation with respect to this
|
||||||
|
CC0 or use of the Work.
|
||||||
|
|
||||||
|
For more information, please see
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0/>
|
||||||
|
|
||||||
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
#include "AudioFile.h"
|
#include "AudioFile.h"
|
||||||
|
|
||||||
|
#define MINIMP3_IMPLEMENTATION
|
||||||
|
#include "minimp3.h"
|
||||||
|
#include "minimp3_ex.h"
|
||||||
|
|
||||||
std::string GetSuffix(const std::string &path)
|
std::string GetSuffix(const std::string &path)
|
||||||
{
|
{
|
||||||
return path.substr(path.find_last_of(".") + 1);
|
return path.substr(path.find_last_of(".") + 1);
|
||||||
|
|
@ -52,6 +56,48 @@ void WavInspector(const std::string &inputFileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Mp3ToWav(const std::string &inputfile, const std::string &outputfile)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
FILE* fp = fopen(inputfile.c_str(), "rb");
|
||||||
|
if (!fp) {
|
||||||
|
printf("Could not open file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long mp3_size = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
uint8_t* mp3_data = new uint8_t[mp3_size];
|
||||||
|
if (fread(mp3_data, 1, mp3_size, fp) == mp3_size)
|
||||||
|
{
|
||||||
|
|
||||||
|
// MP3 to WAV
|
||||||
|
mp3dec_t mp3d;
|
||||||
|
mp3dec_file_info_t info;
|
||||||
|
mp3dec_load_buf(&mp3d, mp3_data, mp3_size, &info, NULL, NULL);
|
||||||
|
|
||||||
|
AudioFile<int16_t> audioFile;
|
||||||
|
|
||||||
|
audioFile.initializeAudioBuffer(info.buffer, info.samples, info.channels);
|
||||||
|
|
||||||
|
audioFile.save(outputfile, AudioFileFormat::Wave);
|
||||||
|
|
||||||
|
free(info.buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Could not read file\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] mp3_data;
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
@ -63,7 +109,7 @@ int main(int argc, char *argv[])
|
||||||
std::string baseName = GetFullBaseName(argv[1]);
|
std::string baseName = GetFullBaseName(argv[1]);
|
||||||
std::string suffix = GetSuffix(argv[1]);
|
std::string suffix = GetSuffix(argv[1]);
|
||||||
|
|
||||||
if(suffix == "wav")
|
if (suffix == "wav")
|
||||||
{
|
{
|
||||||
WavInspector(argv[1]);
|
WavInspector(argv[1]);
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +117,20 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (argc > 2)
|
||||||
|
{
|
||||||
|
std::string suffix = GetSuffix(argv[1]);
|
||||||
|
if (suffix == "mp3")
|
||||||
|
{
|
||||||
|
|
||||||
|
Mp3ToWav(argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
1865
story-editor/tools/audio/minimp3.h
Normal file
1865
story-editor/tools/audio/minimp3.h
Normal file
File diff suppressed because it is too large
Load diff
1397
story-editor/tools/audio/minimp3_ex.h
Normal file
1397
story-editor/tools/audio/minimp3_ex.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue