Refactored audiogen tool

This commit is contained in:
2023-02-13 17:07:24 -08:00
parent f1d13d2e45
commit 0794b8739c
21 changed files with 357 additions and 163 deletions

View File

@ -1,13 +1,13 @@
# Copyright (c) 2022 Dominic Masters # Copyright (c) 2022 Dominic Masters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Check for build target, or default # Check for build target, or default
if(WIN32) if(WIN32)
set(DAWN_BUILD_HOST "build-host-win32") set(DAWN_BUILD_HOST "build-host-win32")
elseif(UNIX AND NOT APPLE) elseif(UNIX AND NOT APPLE)
set(DAWN_BUILD_HOST "build-host-linux64") set(DAWN_BUILD_HOST "build-host-linux64")
endif() endif()
add_subdirectory(${DAWN_BUILD_HOST}) add_subdirectory(${DAWN_BUILD_HOST})

View File

@ -1,6 +1,6 @@
# Copyright (c) 2022 Dominic Masters # Copyright (c) 2022 Dominic Masters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
set(DAWN_BUILD_HOST_LIBS "m" CACHE INTERNAL ${DAWN_CACHE_TARGET}) set(DAWN_BUILD_HOST_LIBS "m" CACHE INTERNAL ${DAWN_CACHE_TARGET})

View File

@ -91,4 +91,5 @@ const dirScan = directory => {
(() => { (() => {
dirScan(DIR_SOURCES); dirScan(DIR_SOURCES);
console.log('Lint done');
})(); })();

View File

@ -1,32 +1,32 @@
// Copyright (c) 2023 Dominic Masters // Copyright (c) 2023 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#include "DeathPrefab.hpp" #include "DeathPrefab.hpp"
using namespace Dawn; using namespace Dawn;
std::string DeathPrefab::getCharacterTexture() { std::string DeathPrefab::getCharacterTexture() {
return "texture_penny"; return "texture_death";
} }
std::string DeathPrefab::getCharacterTileset() { std::string DeathPrefab::getCharacterTileset() {
return "tileset_penny"; return "tileset_death";
} }
std::string DeathPrefab::getLanguagePrefix() { std::string DeathPrefab::getLanguagePrefix() {
return "character.death"; return "character.death";
} }
struct VisualNovelCharacterEmotion DeathPrefab::defineAndGetInitialEmotion( struct VisualNovelCharacterEmotion DeathPrefab::defineAndGetInitialEmotion(
AssetManager *man AssetManager *man
) { ) {
this->emotionHappy.tile = 0; this->emotionHappy.tile = 0;
this->emotionConcerned.tile = 1; this->emotionConcerned.tile = 1;
this->emotionSurprised.tile = 2; this->emotionSurprised.tile = 2;
return this->emotionHappy; return this->emotionHappy;
} }

View File

@ -12,6 +12,7 @@ set(
${DAWN_CACHE_TARGET} ${DAWN_CACHE_TARGET}
) )
# Sources
set(D ${CMAKE_CURRENT_LIST_DIR}) set(D ${CMAKE_CURRENT_LIST_DIR})
set( set(
DAWN_SHARED_SOURCES DAWN_SHARED_SOURCES
@ -20,4 +21,10 @@ set(
CACHE INTERNAL CACHE INTERNAL
${DAWN_CACHE_TARGET} ${DAWN_CACHE_TARGET}
)
# Compile Definitions
set(
DAWN_SHARED_DEFINITIONS
) )

View File

@ -3,6 +3,24 @@
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Tool Level Values
set(
DAWN_TOOL_INCLUDES
${CMAKE_CURRENT_LIST_DIR}
CACHE INTERNAL ${DAWN_CACHE_TARGET}
)
set(
DAWN_TOOL_SOURCES
CACHE INTERNAL
${DAWN_CACHE_TARGET}
)
# Tool-Utils
include(util/CMakeLists.txt)
# Tools
add_subdirectory(audio) add_subdirectory(audio)
add_subdirectory(display) add_subdirectory(display)
add_subdirectory(file) add_subdirectory(file)

View File

@ -1,15 +1,15 @@
# Copyright (c) 2021 Dominic Msters # Copyright (c) 2021 Dominic Msters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
add_subdirectory(audiogen) add_subdirectory(audiogen)
# Texture Tool # Texture Tool
function(tool_audio target in) function(tool_audio target in)
add_custom_target(${target} add_custom_target(${target}
COMMAND audiogen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}/${target}" COMMAND audiogen --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_ASSETS_BUILD_DIR}/${target}"
COMMENT "Generating audio ${target} from ${in}" COMMENT "Generating audio ${target} from ${in}"
DEPENDS audiogen DEPENDS audiogen
) )
endfunction() endfunction()

View File

@ -0,0 +1,60 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AudioGen.hpp"
using namespace Dawn;
std::vector<std::string> AudioGen::getRequiredFlags() {
return std::vector<std::string>{ "input", "output" };
}
int32_t AudioGen::start() {
// Finished with XML data, now we can write data out.
File fileOut(flags["output"] + ".audio");
if(fileOut.exists()) return 0;
// Load input file
AudioFile<double> audioFile;
if(!audioFile.load(flags["input"])) {
printf("Failed to load audio file.\n");
return 1;
}
// Open Output File
fileOut.mkdirp();
if(!fileOut.open(FILE_MODE_WRITE)) {
std::cout << "Failed to open " << fileOut.filename << " output for writing" << std::endl;
return 1;
}
// Write Header
char buffer[FILE_BUFFER_SIZE];
sprintf(buffer, "%i|%i|%i|%i|",
audioFile.getNumChannels(),
audioFile.getSampleRate(),
audioFile.getNumSamplesPerChannel(),
audioFile.getNumSamplesPerChannel() * audioFile.getNumChannels()*(
sizeof(int16_t) / sizeof(uint8_t)
)
);
auto bufferLength = strlen(buffer);
fileOut.writeRaw(buffer, bufferLength);
// Convert Data to 16 bit audio
for (int32_t i = 0; i < audioFile.getNumSamplesPerChannel(); i++) {
for(int32_t y = 0; y < audioFile.getNumChannels(); y++) {
double sample = audioFile.samples[y][i];
sample = sample < -1 ? -1 : sample > 1 ? 1 : sample;
auto q = static_cast<int16_t> (sample * 32767.);
buffer[0] = (q >> 8) & 0xFF;
buffer[1] = q & 0xFF;
fileOut.writeRaw(buffer, 2);
}
}
return 0;
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/File.hpp"
#include "AudioFile.h"
namespace Dawn {
class AudioGen : public DawnTool {
protected:
std::vector<std::string> getRequiredFlags() override;
public:
int32_t start();
};
}

View File

@ -6,17 +6,32 @@
# Texture Build Tool # Texture Build Tool
project(audiogen VERSION 1.0) project(audiogen VERSION 1.0)
add_executable(audiogen) add_executable(audiogen)
# Sources
target_sources(audiogen target_sources(audiogen
PRIVATE PRIVATE
main.cpp ${DAWN_SHARED_SOURCES}
../../util/file.cpp ${DAWN_TOOL_SOURCES}
AudioGen.cpp
) )
# Includes
target_include_directories(audiogen target_include_directories(audiogen
PUBLIC PUBLIC
${DAWN_SHARED_INCLUDES} ${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../ ${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
) )
# Definitions
target_compile_definitions(audiogen
PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=AudioGen
DAWN_TOOL_HEADER="AudioGen.hpp"
)
# Libraries
target_link_libraries(audiogen target_link_libraries(audiogen
PUBLIC PUBLIC
${DAWN_BUILD_HOST_LIBS} ${DAWN_BUILD_HOST_LIBS}

View File

@ -1,76 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "dawnsharedlibs.hpp"
#include "../../util/file.hpp"
#include "AudioFile.h"
int main(int argc, char *argv[]) {
FILE *fileOut;
char buffer[FILENAME_MAX];
size_t bufferLength = 0;
if(argc != 3) {
printf("Invalid number of arguments\n");
return 1;
}
fileNormalizeSlashes(argv[1]);
fileNormalizeSlashes(argv[2]);
std::string strFileIn = std::string(argv[1]);
std::string strFileOut = std::string(argv[2]);
buffer[0] = '\0';
sprintf(buffer, "%s.audio", strFileOut.c_str());
fileOut = fopen(buffer, "rb");
if(fileOut != NULL) {
fclose(fileOut);
return 0;
}
// Load input file
AudioFile<double> audioFile;
if(!audioFile.load(strFileIn)) {
printf("Failed to load audio file.\n");
return 1;
}
// Open Output File
fileMkdirp(buffer);
fileOut = fopen(buffer, "wb");
if(fileOut == NULL) {
printf("Failed to create output file\n");
return 1;
}
// Write header
buffer[0] = '\0';
sprintf(buffer, "%i|%i|%i|%i|",
audioFile.getNumChannels(),
audioFile.getSampleRate(),
audioFile.getNumSamplesPerChannel(),
audioFile.getNumSamplesPerChannel() * audioFile.getNumChannels()*(
sizeof(int16_t) / sizeof(uint8_t)
)
);
bufferLength = strlen(buffer);
fwrite(buffer, sizeof(char), bufferLength, fileOut);
// Convert Data to 16 bit audio
for (int32_t i = 0; i < audioFile.getNumSamplesPerChannel(); i++) {
for(int32_t y = 0; y < audioFile.getNumChannels(); y++) {
double sample = audioFile.samples[y][i];
sample = sample < -1 ? -1 : sample > 1 ? 1 : sample;
auto q = static_cast<int16_t> (sample * 32767.);
buffer[0] = (q >> 8) & 0xFF;
buffer[1] = q & 0xFF;
fwrite(buffer, sizeof(uint8_t), 2, fileOut);
}
}
fclose(fileOut);
return 0;
}

View File

@ -0,0 +1,12 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
set(D ${CMAKE_CURRENT_LIST_DIR})
list(APPEND
DAWN_TOOL_SOURCES
${D}/DawnTool.cpp
${D}/File.cpp
)

View File

@ -17,9 +17,53 @@
using namespace Dawn; using namespace Dawn;
std::vector<std::string> DawnTool::getRequiredFlags() {
return std::vector<std::string>();
}
std::map<std::string, std::string> DawnTool::getOptionalFlags() {
return std::map<std::string, std::string>();
}
int32_t DawnTool::exec(const int32_t argc, const char *argv[]) { int32_t DawnTool::exec(const int32_t argc, const char *argv[]) {
// Set up flags
flags = this->getOptionalFlags();
// Parse args
for(int32_t i = 0; i < argc; i++) { for(int32_t i = 0; i < argc; i++) {
this->args.push_back(std::string(argv[i])); std::string a(argv[i]);
this->args.push_back(a);
// First arg is the path, we ignore it.
if(i == 0) continue;
// Is this a flag-like arg, as in has "--[name]=[value]"
if(a.size() < 5) continue;
if(a[0] != '-' || a[1] != '-') continue;
// Remove --
auto flag = a.erase(0, 2);
// Ensure = is present
auto equalPos = flag.find('=');
if(equalPos == std::string::npos) continue;
// Get prefix and val and store
auto prefix = flag.substr(0, equalPos);
auto val = flag.substr(equalPos + 1);
flags[prefix] = val;
}
// Now validate flags
auto required = this->getRequiredFlags();
auto itReq = required.begin();
while(itReq != required.end()) {
auto match = flags.find(*itReq);
if(match == flags.end()) {
std::cout << "Missing required flag \"" + *itReq + "\"!" << std::endl;
return 1;
}
++itReq;
} }
return this->start(); return this->start();

View File

@ -18,6 +18,10 @@ namespace Dawn {
class DawnTool { class DawnTool {
protected: protected:
std::vector<std::string> args; std::vector<std::string> args;
std::map<std::string, std::string> flags;
virtual std::vector<std::string> getRequiredFlags();
virtual std::map<std::string, std::string> getOptionalFlags();
public: public:
int32_t exec(const int32_t argc, const char *argv[]); int32_t exec(const int32_t argc, const char *argv[]);

View File

@ -7,8 +7,50 @@
using namespace Dawn; using namespace Dawn;
std::string File::normalizeSlashes(std::string str) {
size_t i = 0;
while(i < str.size()) {
auto c = str[i];
if(c == '\\' || c == '/') str[i] = FILE_PATH_SEP;
++i;
}
return str;
}
void File::mkdirp(std::string path) {
std::string buffer;
char c;
size_t i = 0;
bool inFile;
bool hasMore;
inFile = false;
hasMore = false;
while(c = path[i]) {
if((c == '\\' || c == '/') && i > 0) {
fileMkdir(buffer.c_str(), 0755);
inFile = false;
hasMore = false;
buffer += FILE_PATH_SEP;
i++;
continue;
}
if(c == '.') inFile = true;
hasMore = true;
buffer += c;
i++;
}
if(!inFile && hasMore) {
fileMkdir(buffer.c_str(), 0755);
}
}
//
File::File(std::string filename) { File::File(std::string filename) {
this->filename = fileNormalizeSlashesNew(filename); this->filename = File::normalizeSlashes(filename);
} }
bool_t File::open(enum FileMode mode) { bool_t File::open(enum FileMode mode) {
@ -42,6 +84,14 @@ bool_t File::isOpen() {
return this->file != nullptr; return this->file != nullptr;
} }
bool_t File::exists() {
if(this->file != nullptr) return true;
FILE *f = fopen(this->filename.c_str(), "rb");
if(f == NULL || f == nullptr) return false;
fclose(f);
return true;
}
void File::close() { void File::close() {
assertNotNull(this->file); assertNotNull(this->file);
fclose(this->file); fclose(this->file);
@ -49,7 +99,7 @@ void File::close() {
} }
bool_t File::mkdirp() { bool_t File::mkdirp() {
fileMkdirp((char*)this->filename.c_str()); File::mkdirp(this->filename);
return true; return true;
} }
@ -81,10 +131,15 @@ bool_t File::writeString(std::string in) {
if(!this->open(FILE_MODE_WRITE)) return false; if(!this->open(FILE_MODE_WRITE)) return false;
} }
assertTrue(this->mode == FILE_MODE_WRITE); assertTrue(this->mode == FILE_MODE_WRITE);
return this->writeRaw((char *)in.c_str(), in.size()) && this->length == in.size();
}
const char_t *strOut = in.c_str(); bool_t File::writeRaw(char *data, size_t len) {
// TODO: Validate write length. if(!this->isOpen()) {
this->length = fwrite(strOut, sizeof(char_t), in.size(), this->file); if(!this->open(FILE_MODE_WRITE)) return false;
}
assertTrue(this->mode == FILE_MODE_WRITE);
this->length = fwrite(data, sizeof(char_t), len, this->file);
return true; return true;
} }

View File

@ -5,9 +5,22 @@
#pragma once #pragma once
#include "assert/assert.hpp" #include "assert/assert.hpp"
#include "util/file.hpp"
#include "util/mathutils.hpp" #include "util/mathutils.hpp"
#if defined(_MSC_VER)
#include <direct.h>
#include <windows.h>
#define getcwd _getcwd
#define FILE_PATH_SEP '\\'
#define fileMkdir(path, perms) _mkdir(path)
#elif defined(__GNUC__)
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#define FILE_PATH_SEP '/'
#define fileMkdir(path, perms) mkdir(path, perms)
#endif
#define FILE_BUFFER_SIZE 512 #define FILE_BUFFER_SIZE 512
namespace Dawn { namespace Dawn {
@ -23,6 +36,9 @@ namespace Dawn {
size_t length; size_t length;
public: public:
static std::string normalizeSlashes(std::string str);
static void mkdirp(std::string path);
std::string filename; std::string filename;
/** /**
@ -47,6 +63,14 @@ namespace Dawn {
*/ */
bool_t isOpen(); bool_t isOpen();
/**
* Returns whether or not the file exists. Will open the connection if it
* does exist.
*
* @return True if exists, otherwsie if it doesn't.
*/
bool_t exists();
/** /**
* Closes the currently open interface to the file. Done automatically * Closes the currently open interface to the file. Done automatically
* when this object is disposed. * when this object is disposed.
@ -78,6 +102,14 @@ namespace Dawn {
*/ */
bool_t writeString(std::string in); bool_t writeString(std::string in);
/**
* Write raw bytes to the file.
*
* @param data Data to write.
* @return True if written successfully, otherwise false.
*/
bool_t writeRaw(char *data, size_t );
~File(); ~File();
}; };
} }

View File

@ -74,4 +74,4 @@ int32_t skipAhead(
char *needles, int32_t needleCount char *needles, int32_t needleCount
); );
std::string fileNormalizeSlashesNew(std::string str); static std::string fileNormalizeSlashesNew(std::string str);

View File

@ -8,7 +8,7 @@ add_subdirectory(vnscenegen)
# UI Tool # UI Tool
function(tool_vnscene target in) function(tool_vnscene target in)
add_custom_target(${target} add_custom_target(${target}
COMMAND vnscenegen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_GENERATED_DIR}/scenes/${target}" COMMAND vnscenegen --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_GENERATED_DIR}/scenes/${target}"
COMMENT "Generating VN Scene ${target} from ${in}" COMMENT "Generating VN Scene ${target} from ${in}"
DEPENDS vnscenegen DEPENDS vnscenegen
) )

View File

@ -3,32 +3,35 @@
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Texture Build Tool # VN Scene Generator Tool
project(vnscenegen VERSION 1.1) project(vnscenegen VERSION 1.1)
add_executable(vnscenegen) add_executable(vnscenegen)
# Sources
target_sources(vnscenegen target_sources(vnscenegen
PRIVATE PRIVATE
${DAWN_SHARED_SOURCES} ${DAWN_SHARED_SOURCES}
${DAWN_TOOL_SOURCES}
VnSceneGen.cpp VnSceneGen.cpp
../../util/DawnTool.cpp
../../util/File.cpp
../../util/file.cpp
../../util/xml.cpp
) )
# Includes
target_include_directories(vnscenegen target_include_directories(vnscenegen
PUBLIC PUBLIC
${DAWN_SHARED_INCLUDES} ${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../ ${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
) )
# Definitions
target_compile_definitions(vnscenegen target_compile_definitions(vnscenegen
PUBLIC PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=VnSceneGen DAWN_TOOL_INSTANCE=VnSceneGen
DAWN_TOOL_HEADER="VnSceneGen.hpp" DAWN_TOOL_HEADER="VnSceneGen.hpp"
) )
# Libraries
target_link_libraries(vnscenegen target_link_libraries(vnscenegen
PUBLIC PUBLIC
${DAWN_BUILD_HOST_LIBS} ${DAWN_BUILD_HOST_LIBS}

View File

@ -7,14 +7,13 @@
using namespace Dawn; using namespace Dawn;
int32_t VnSceneGen::start() { std::vector<std::string> VnSceneGen::getRequiredFlags() {
if(this->args.size() != 3) { return std::vector<std::string>{ "input", "output" };
std::cout << "Invalid number of args passed to VNScene Generator" << std::endl; }
return 1;
}
int32_t VnSceneGen::start() {
// Open input file. // Open input file.
File file(this->args[1]); File file(flags["input"]);
std::string buffer; std::string buffer;
if(!file.readString(&buffer)) { if(!file.readString(&buffer)) {
std::cout << "Failed to read scene " << file.filename << std::endl; std::cout << "Failed to read scene " << file.filename << std::endl;
@ -43,7 +42,7 @@ int32_t VnSceneGen::start() {
} }
// Finished with XML data, now we can write data out. // Finished with XML data, now we can write data out.
File fileOut(this->args[2] + ".hpp"); File fileOut(flags["output"] + ".hpp");
if(!fileOut.mkdirp()) { if(!fileOut.mkdirp()) {
std::cout << "Failed to make scene output dir" << std::endl; std::cout << "Failed to make scene output dir" << std::endl;
return 1; return 1;

View File

@ -11,6 +11,7 @@
namespace Dawn { namespace Dawn {
class VnSceneGen : public DawnTool { class VnSceneGen : public DawnTool {
protected: protected:
std::vector<std::string> getRequiredFlags() override;
public: public:
int32_t start(); int32_t start();