diff --git a/CMakeLists.txt b/CMakeLists.txt index bd6bf03..f653ae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ project(opendspx VERSION 0.0.1.5 LANGUAGES C CXX) # ---------------------------------- option(OPENDSPX_BUILD_STATIC "Build static library" OFF) option(OPENDSPX_BUILD_TESTS "Build test cases" OFF) +option(OPENDSPX_BUILD_INTERPOLATOR "Build interpolator" ON) option(OPENDSPX_BUILD_SERIALIZER "Build serializer" ON) option(OPENDSPX_BUILD_CONVERTER "Build converter" ON) option(OPENDSPX_INSTALL "Install library" ON) @@ -58,18 +59,23 @@ set(OPENDSPX_INSTALL_NAME ${PROJECT_NAME}) set(CMAKE_POSITION_INDEPENDENT_CODE on) set(OPENDSPX_MODEL_TARGET ${PROJECT_NAME}model) +set(OPENDSPX_INTERPOLATOR_TARGET ${PROJECT_NAME}interpolator) set(OPENDSPX_SERIALIZER_TARGET ${PROJECT_NAME}serializer) set(OPENDSPX_CONVERTER_TARGET ${PROJECT_NAME}converter) set(CURRENT_YEAR) string(TIMESTAMP CURRENT_YEAR "%Y") -find_package(QT NAMES Qt6 COMPONENTS Core REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) +find_package(nlohmann_json CONFIG REQUIRED) +find_package(stdcorelib CONFIG REQUIRED) +if(OPENDSPX_BUILD_SERIALIZER) + find_package(zstd CONFIG REQUIRED) +endif() + if (WIN32) include(cmake/winrc.cmake) endif() -if (TRUE) +if(TRUE) # Add library add_library(${OPENDSPX_MODEL_TARGET} INTERFACE) add_library(${PROJECT_NAME}::model ALIAS ${OPENDSPX_MODEL_TARGET}) @@ -83,7 +89,7 @@ if (TRUE) ) # Link libraries - target_link_libraries(${OPENDSPX_MODEL_TARGET} INTERFACE Qt${QT_VERSION_MAJOR}::Core) + target_link_libraries(${OPENDSPX_MODEL_TARGET} INTERFACE nlohmann_json::nlohmann_json) if (OPENDSPX_INSTALL) target_include_directories(${OPENDSPX_MODEL_TARGET} INTERFACE @@ -96,8 +102,38 @@ if (TRUE) LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" OPTIONAL ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" OPTIONAL ) - endif () -endif () + endif() +endif() + +if(OPENDSPX_BUILD_INTERPOLATOR) + # Add library + add_library(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE) + add_library(${PROJECT_NAME}::interpolator ALIAS ${OPENDSPX_INTERPOLATOR_TARGET}) + + # Add features + target_compile_features(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE cxx_std_20 cxx_std_17) + + # Include directories + target_include_directories(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE + "$" + ) + + # Link libraries + target_link_libraries(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE nlohmann_json::nlohmann_json) + + if (OPENDSPX_INSTALL) + target_include_directories(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE + "$" + ) + + install(TARGETS ${OPENDSPX_INTERPOLATOR_TARGET} + EXPORT ${OPENDSPX_INSTALL_NAME}Targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" OPTIONAL + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" OPTIONAL + ) + endif() +endif() macro(_opendspx_add_library identifier) string(TOUPPER "${identifier}" IDENTIFIER) @@ -126,8 +162,8 @@ macro(_opendspx_add_library identifier) ) target_include_directories(${OPENDSPX_${IDENTIFIER}_TARGET} PRIVATE include/opendspx${identifier}) - target_link_libraries(${OPENDSPX_${IDENTIFIER}_TARGET} PUBLIC Qt${QT_VERSION_MAJOR}::Core) target_link_libraries(${OPENDSPX_${IDENTIFIER}_TARGET} PUBLIC ${OPENDSPX_MODEL_TARGET}) + target_link_libraries(${OPENDSPX_${IDENTIFIER}_TARGET} PRIVATE stdcorelib::stdcorelib) # Add platform specific if (WIN32) @@ -154,6 +190,7 @@ endmacro() if (OPENDSPX_BUILD_SERIALIZER) _opendspx_add_library(serializer) + target_link_libraries(${OPENDSPX_SERIALIZER_TARGET} PRIVATE zstd::libzstd) endif() if (OPENDSPX_BUILD_CONVERTER) diff --git a/README.md b/README.md index cfff62c..04a4e78 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,145 @@ # OpenDSPX -DiffScope data exchange format. +OpenDSPX is a C++20 library for working with the [DSPX format](https://dspx.diffscope.org/). +It provides four layers: + +- `model`: the core DSPX data model and headers +- `interpolator`: DSPX parameter curve interpolation utilities for evaluating parameter values +- `serializer`: serialization and deserialization for DSPX files +- `converter`: DSPX format conversion utilities built on top of the model layer; MIDI is the first supported backend today ## Requirements -+ C++ 17 -+ CMake 3.19 - -## Dependencies -+ [qastool](https://github.com/SineStriker/qt-json-autogen) -+ [stdutau](https://github.com/diffscope/stdutau) -+ [qnrbf](https://github.com/SineStriker/QNrbf) - + `QtCore` is required -+ [QMidi](https://github.com/waddlesplash/QMidi) - + `QtCore` is required - -## Supported Formats - -+ UTAU UST -+ OpenSVIP -+ Xiaobin XStudio SVIP (<=2.0) \ No newline at end of file + +Build-time dependencies: + +- CMake 3.17 or newer +- A C++20-capable compiler +- `nlohmann-json` +- `stdcorelib` +- `zstd` for the serializer module +- `wolf-midi` for the converter module + +The project is currently configured for Windows and other CMake-supported platforms. + +## Build + +Configure and build with CMake: + +```bash +cmake -S . -B build +cmake --build build +``` + +Useful options: + +- `OPENDSPX_BUILD_STATIC`: build static libraries instead of shared libraries +- `OPENDSPX_BUILD_TESTS`: build the test executable +- `OPENDSPX_BUILD_INTERPOLATOR`: build the interpolator interface library +- `OPENDSPX_BUILD_SERIALIZER`: build the serializer library +- `OPENDSPX_BUILD_CONVERTER`: build the converter library +- `OPENDSPX_INSTALL`: generate install rules and CMake package files + +## Using OpenDSPX + +### Core model + +The core data type is `opendspx::Model`. It currently exposes version `V1` and the associated DSPX content tree. + +## Interpolator + +The interpolator module is a header-only utility for building and evaluating cubic curves. +It is useful for DSPX parameter evaluation. + +The public API provides helpers for: + +- creating a curve from two key points plus reference points +- creating a curve from only one side of reference data +- creating a linear interpolator +- evaluating the resulting curve at any x position + +Example: + +```cpp +#include + +using opendspx::Interpolator; + +int main() { + auto curve = Interpolator::createLinear(0.0, 0.0, 1.0, 1.0); + double value = curve.evaluate(0.5); + (void)value; +} +``` + +### Serialization + +Use `opendspx::Serializer` to convert between `Model` and DSPX data streams. + +```cpp +#include +#include +#include + +using namespace opendspx; + +int main() { + std::ifstream input("song.dspx", std::ios::binary); + SerializationErrorList errors; + + Model model = Serializer::deserialize(input, errors); + + std::ofstream output("song-out.dspx", std::ios::binary); + Serializer::serialize(output, model, errors); +} +``` + +`Serializer::serialize` can also write compressed output when the `compress` flag is set to `true`. + +### DSPX format conversion + +Use `opendspx::Converter` to convert between DSPX data and other formats. + +```cpp +#include +#include + +using namespace opendspx; + +int main() { + Model model; + + auto intermediate = MidiConverter::convertDspxToIntermediate(model); + std::ofstream midiOutput("output.mid", std::ios::binary); + MidiConverter::convertIntermediateToMidi(midiOutput, intermediate); + + MidiConverter::Error error; + std::ifstream midiInput("input.mid", std::ios::binary); + auto imported = MidiConverter::convertMidiToIntermediate(midiInput, error); + if (error != MidiConverter::Error::NoError) { + return 1; + } + + bool ok = false; + Model roundTrip = MidiConverter::convertIntermediateToDspx(imported, &ok); + if (!ok) { + return 1; + } + + (void)roundTrip; +} +``` + +## Project Structure + +- `include/opendspx/`: public model headers +- `include/opendspxinterpolator/`: interpolator API +- `include/opendspxserializer/`: serializer API +- `include/opendspxconverter/`: converter API +- `src/serializer/`: serializer implementation +- `src/converter/`: converter implementation, currently focused on MIDI +- `tests/`: usage tests + +## License + +This project is distributed under the Apache License, Version 2.0, as described in [LICENSE](LICENSE). + diff --git a/docs/dspx-example.json b/docs/dspx-example.json deleted file mode 100644 index 9dacb81..0000000 --- a/docs/dspx-example.json +++ /dev/null @@ -1,222 +0,0 @@ -{ - "version": "1.0.0", - "content": { - "global": { - "author": "作者", - "name": "这是一个示例工程", - "centShift": 0 - }, - "master": { - "control": { - "gain": 0, - "pan": 0, - "mute": false - } - }, - "timeline": { - "timeSignatures": [ - { - "index": 0, - "numerator": 4, - "denominator": 4 - } - ], - "tempos": [ - { - "pos": 0, - "value": 120 - } - ], - "labels": [ - { - "pos": 1440, - "text": "开始" - } - ] - }, - "tracks": [ - { - "name": "主音轨", - "control": { - "gain": 1, - "pan": 0, - "mute": false, - "solo": false - }, - "clips": [ - { - "type": "singing", - "time": { - "start": 0, - "length": 300000, - "clipStart": 1000, - "clipLen": 20000 - }, - "name": "样式 1", - "control": { - "gain": 1, - "pan": 0, - "mute": false - }, - "sources": { - "acoustic": { - "uri": "localhost:2333", - "id": 3, - "name": "夏叶子" - }, - "variance": { - "id": 1 - } - }, - "notes": [ - { - "pos": 480, - "length": 480, - "keyNum": 60, - "centShift": 0, - "language": "zh_CN", - "lyric": "拉", - "pronunciation": { - "original": "la", - "edited": null - }, - "phonemes": { - "original": [ - { - "type": "ahead", - "token": "zh", - "start": 0 - }, - { - "type": "normal", - "token": "u", - "start": 5 - }, - { - "type": "final", - "token": "ang", - "start": 10 - } - ], - "edited": [] - }, - "vibrato": { - "start": 0.1, - "end": 0.8, - "freq": 5, - "phase": 0.5, - "amp": 1.1, - "offset": 0.1, - "points": [ - { - "x": 0.2, - "y": 1 - }, - { - "x": 0.8, - "y": 1 - } - ] - }, - "extra": { - "render": { - "seed": 0, - "speedUp": 100 - } - } - } - ], - "params": { - "pitch": { - "original": [ - { - "type": "free", - "start": 100, - "step": 5, - "values": [ - 114, - 514 - ] - } - ], - "edited": [ - { - "type": "anchor", - "start": 0, - "nodes": [ - { - "x": 114, - "y": 514, - "interp": "linear" - }, - { - "x": 1919, - "y": 810, - "interp": "hermite" - }, - { - "x": 3330, - "y": 0, - "interp": "none" - } - ] - }, - { - "type": "free", - "start": 3500, - "step": 5, - "values": [ - 0, - 1 - ] - } - ] - }, - "energy": { - "original": [], - "edited": [], - "envelope": [] - } - } - } - ], - "color": { - "value": "#3B7FFF" - } - }, - { - "name": "音乐轨", - "control": { - "gain": 1, - "pan": 0, - "mute": false, - "solo": false - }, - "clips": [ - { - "type": "audio", - "time": { - "start": 0, - "length": 0, - "clipStart": 1000, - "clipLen": 20000 - }, - "name": "BGM_1", - "control": { - "gain": 1, - "mute": false - }, - "path": "/path/to/bgm.wav" - } - ], - "color": { - "id": 1 - } - } - ] - }, - "workspace": { - "core": {}, - "plugin1": {} - } -} \ No newline at end of file diff --git a/docs/dspx-spec.md b/docs/dspx-spec.md deleted file mode 100644 index 0dfa7e7..0000000 --- a/docs/dspx-spec.md +++ /dev/null @@ -1,399 +0,0 @@ -# DSPX 格式简介 - ---- - -## 根区域 - -```json -{ - "version": "1.0.0", - "content": { - ... - } -} -``` -+ `version`:文件版本号 -+ `content`:工程可编辑区域,见下 - -## 可编辑区域 - -```json -{ - "global": { - "name": "New Project", - "author": "Admin", - "centShift": 0, - }, - "master": { - "control": { - "gain": 0, - "pan": 0, - "mute": false - } - }, - "timeline": { - "timeSignatures": [ - ... - ], - "tempos": [ - ... - ], - "labels": [ - ... - ] - }, - "tracks": [ - ... - ], - "workspace": { - ... - } -} -``` -+ `global`: 元信息 - + `name`: 工程名 - + `author`: 作者 - + `centShift`:全局音分偏移 -+ `master`:总线控制 - + `control`: 全局主控 - + `gain`:增益,`double` - + `pan`:声像(-1~1),`double` - + `mute`:静音 - -+ `timeline`:时间轴 - + `timeSignatures`:拍号列表 - + `tempos`:曲速列表 - + `labels`:标签;列表 -+ `tracks`:音轨列表 -+ `workspace`:应用程序状态信息 - -## 拍号 - -```json -{ - "index": 0, - "numerator": 4, - "denominator": 4 -} -``` -+ `index`:位置(bar),`int` -+ `numerator`:分子,`int` -+ `denominator`:分母,`int` - -## 曲速 - -```json -{ - "pos": 0, - "value": 120.0 -} -``` -+ `pos`:位置(tick),`int` -+ `value`:曲速值,`double` - -## 标签 - -```json -{ - "pos": 480, - "text": "张三" -} -``` -+ `pos`:位置(tick),`int` -+ `text`:标签内容 - -## 音轨 - -```json -{ - "name": "主音轨", - "control": { - "gain": 0, - "pan": 0, - "mute": false, - "solo": false - }, - "clips": [ - ... - ], - "color": { - ... - }, - "workspace": { - ... - } -} -``` - -+ `name`:主控 -+ `control`: 音轨主控 - + `gain`:增益,`double` - + `mute`:静音 - + `solo`:独奏 -+ `clips`:音轨区间列表,暂有音频区间、人声区间 -+ `color`: 音轨颜色信息 - + 自定义: - ```json - "value": "#3B7FFF" - ``` - + 内置: - ```json - "id": "1" - ``` -+ `workspace`: 应用程序状态信息 - -## 音频区间 - -```json -{ - "type": "audio", - "time": { - "start": 0, - "length": 0, - "clipStart": 1000, - "clipLen": 20000 - }, - "name": "BGM_1", - "control": { - "gain": 1, - "pan": 0, - "mute": false - }, - "path": "/path/to/bgm.wav", - "workspace": { - ... - } -} -``` - -+ `type`:类型,固定值 -+ `time`: 时间信息 - + `start`:区间开始(tick),`int` - + `length`:固定为0,`int` - + `clipStart`:实际开始,相对于区间开始的长度(tick),`int` - + `clipLen`:实际长度,相对于实际开始的长度(tick),`int` -+ `name`:音轨名 -+ `control`:与主控一致 -+ `path`:音频文件所在路径 -+ `workspace`: 应用程序状态信息 - -## 人声区间 - -```json -{ - "type": "singing", - "time": { - "start": 0, - "length": 300000, - "clipStart": 1000, - "clipLen": 20000 - }, - "name": "样式 1", - "control": { - "gain": 1, - "mute": false - }, - "notes": [ - ... - ], - "params": { - "pitch": { - "original": [ - ... - ], - "edited": [ - ... - ] - }, - "energy": { - "original": [ - ... - ], - "edited": [ - ... - ], - "envelope": [ - ... - ] - }, - ... - }, - "sources": { - "acoustic": { - "model": "mousse", - "speaker": { - "s1": 30, - "s2": 30, - "s3": 40 - } - }, - "pitch": { - ... - }, - ... - }, - "workspace": { - ... - } -} -``` - -+ `type`:类型,固定值 -+ `time`: 时间信息 - + `length`:区间全长(tick) -+ `notes`:音符列表 -+ `params`:单线条参数 - + `pitchDelta`:音高偏差 - + `original`:自动参数列表 - + `edited`:已修改的参数列表 - + `envelope`: 在实参上的包络(音高参数没有这个属性) -+ `sources`:使用到的模型 -+ `workspace`: 应用程序状态信息 - -## 音符 - -```json -{ - "pos": 480, - "length": 480, - "keyNum": 60, - "centShift": 0, - "language": "zh_CN", - "lyric": "拉", - "pronunciation": { - "original": "la", - "edited": null - }, - "phonemes": { - "original": [ - ... - ], - "edited": [ - ... - ] - }, - "vibrato": { - "start": 0.1, - "end": 0.8, - "freq": 1, - "phase": 0.5, - "amplitude": 1.1, - "offset": 0.1, - "points": [ - { - "x": 0.2, - "y": 0.8 - }, - { - "x": 0.8, - "y": 1 - } - ] - }, - "workspace": { - ... - } -} -``` - -+ `pos`:位置(tick),`int` -+ `length`:长度(tick),`int` -+ `keyNum`:音阶 -+ `centShift`:音分偏移 -+ `language`: 语言(待定) -+ `lyric`:歌词 -+ `pronunciation`: 发音 - `original`:G2P 自动生成的发音 - `edited`:用户修改后的发音 -+ `phonemes`:音素 - `original`:自动参数列表 - `edited`:已修改的参数列表 -+ `vibrato`:颤音 - + `start`:开始(音符比例),`double` - + `end`:结束(音符比例),`double` - + `freq`:频率(Hz),`double` - + `phase`:相位(0~1),`double` - + `amp`:振幅(半音倍率),`double` - + `offset`:音高偏移(半音倍率),`double` - + `points`:控制点列表,一般只有两个点 - + `x`:颤音长度比例(0~1),`double` - + `y`:颤音振幅比例(0~1),`double` -+ `workspace`: 应用程序状态信息 - -## 音素 - -```json -{ - "type": "ahead", - "token": "ang", - "start": 5 -} -``` - -+ `type`:类型,`ahead`、`normal`或`final` -+ `token`:音素符号 -+ `start`:相对当前音符头的开始时间(ms),`int` - -## 单线条参数 - -### 手绘型 - -```json -{ - "type": "free", - "start": 100, - "step": 5, - "values": [ - 114, - 514 - ] -} -``` -+ `type`:类型,固定值 -+ `start`:开始(tick),`int` -+ `step`:采样步长,固定为5,`int` -+ `values`:音高坐标(1/100个半音),`int` - -### 锚点型 - -```json - { - "type": "anchor", - "start": 100, - "nodes": [ - { - "x": 114, - "y": 514, - "interp": "linear" - }, - { - "x": 1919, - "y": 810, - "interp": "hermite" - }, - { - "x": 0, - "y": 0, - "interp": null - } - ] -} -``` - -+ `type`:类型,固定值 -+ `start`:开始(tick),`int` -+ `nodes`:参数列表 - + `x`:时间坐标(Tick),`int` - + `y`:音高坐标(1/100个半音),`int` - + `interp`:插值方式 - -## 其他 - -### 单线条参数种类 - -+ `pitch`:音高曲线参数,`y`的值为绝对音高,如`C4`为`6000` -+ `energy`: 力度曲线 -+ ... \ No newline at end of file diff --git a/include/opendspx/anchornode.h b/include/opendspx/anchornode.h index 2cfc441..d4f7ad9 100644 --- a/include/opendspx/anchornode.h +++ b/include/opendspx/anchornode.h @@ -1,15 +1,15 @@ #ifndef OPENDSPX_MODEL_ANCHORNODE_H #define OPENDSPX_MODEL_ANCHORNODE_H -namespace QDspx { +namespace opendspx { struct AnchorNode { - enum Interpolation { + enum class Interpolation { None, Linear, Hermite, }; - Interpolation interp{None}; + Interpolation interp{Interpolation::None}; int x{0}; int y{0}; }; diff --git a/include/opendspx/audioclip.h b/include/opendspx/audioclip.h index 08a74e2..565445d 100644 --- a/include/opendspx/audioclip.h +++ b/include/opendspx/audioclip.h @@ -3,16 +3,18 @@ #include -namespace QDspx { +#include + +namespace opendspx { struct AudioClip : Clip { - AudioClip(const QString &name = {}, const BusControl &control = {}, const ClipTime &time = {}, const Workspace &workspace = {}, const QString &path = {}) - : Clip(Audio, name, control, time, workspace), path(path) { + AudioClip(std::string name = {}, const BusControl &control = {}, const ClipTime &time = {}, Workspace workspace = {}, std::string path = {}) + : Clip(Type::Audio, std::move(name), control, time, std::move(workspace)), path(std::move(path)) { } - QString path; + std::string path; }; - using AudioClipRef = QSharedPointer; + using AudioClipRef = std::shared_ptr; } diff --git a/include/opendspx/buscontrol.h b/include/opendspx/buscontrol.h index 2a4eb25..0377e27 100644 --- a/include/opendspx/buscontrol.h +++ b/include/opendspx/buscontrol.h @@ -1,7 +1,7 @@ #ifndef OPENDSPX_MODEL_BUSCONTROL_H #define OPENDSPX_MODEL_BUSCONTROL_H -namespace QDspx { +namespace opendspx { struct BusControl { double gain{0.0}; diff --git a/include/opendspx/clip.h b/include/opendspx/clip.h index b5097ad..4b5550f 100644 --- a/include/opendspx/clip.h +++ b/include/opendspx/clip.h @@ -1,33 +1,34 @@ #ifndef OPENDSPX_MODEL_CLIP_H #define OPENDSPX_MODEL_CLIP_H -#include -#include +#include +#include +#include #include #include #include -namespace QDspx { +namespace opendspx { struct Clip { - enum Type { + enum class Type { Audio, Singing, }; Type type; - QString name; + std::string name; BusControl control; ClipTime time; Workspace workspace; protected: - Clip(Type type, const QString &name = {}, const BusControl &control = {}, const ClipTime &time = {}, const Workspace &workspace = {}) - : type(type), name(name), control(control), time(time), workspace(workspace) { + Clip(Type type, std::string name = {}, const BusControl &control = {}, const ClipTime &time = {}, Workspace workspace = {}) + : type(type), name(std::move(name)), control(control), time(time), workspace(std::move(workspace)) { } }; - using ClipRef = QSharedPointer; + using ClipRef = std::shared_ptr; } diff --git a/include/opendspx/cliptime.h b/include/opendspx/cliptime.h index e9801f2..3916ad0 100644 --- a/include/opendspx/cliptime.h +++ b/include/opendspx/cliptime.h @@ -1,10 +1,10 @@ #ifndef OPENDSPX_MODEL_CLIPTIME_H #define OPENDSPX_MODEL_CLIPTIME_H -namespace QDspx { +namespace opendspx { struct ClipTime { - int start{0}; + int pos{0}; int length{0}; int clipStart{0}; int clipLen{0}; diff --git a/include/opendspx/content.h b/include/opendspx/content.h index 5d579d1..6d7d23c 100644 --- a/include/opendspx/content.h +++ b/include/opendspx/content.h @@ -1,7 +1,7 @@ #ifndef OPENDSPX_MODEL_CONTENT_H #define OPENDSPX_MODEL_CONTENT_H -#include +#include #include #include @@ -9,13 +9,13 @@ #include #include -namespace QDspx{ +namespace opendspx{ struct Content { Global global; Master master; Timeline timeline; - QList tracks; + std::vector tracks; Workspace workspace; }; diff --git a/include/opendspx/controlpoint.h b/include/opendspx/controlpoint.h index 0e02d15..70dc65f 100644 --- a/include/opendspx/controlpoint.h +++ b/include/opendspx/controlpoint.h @@ -1,7 +1,7 @@ #ifndef OPENDSPX_MODEL_CONTROLPOINT_H #define OPENDSPX_MODEL_CONTROLPOINT_H -namespace QDspx { +namespace opendspx { struct ControlPoint { double x{0.0}; diff --git a/include/opendspx/dynamicmixinganchor.h b/include/opendspx/dynamicmixinganchor.h new file mode 100644 index 0000000..7d7f17f --- /dev/null +++ b/include/opendspx/dynamicmixinganchor.h @@ -0,0 +1,15 @@ +#ifndef OPENDSPX_MODEL_DYNAMICMIXINGANCHOR_H +#define OPENDSPX_MODEL_DYNAMICMIXINGANCHOR_H + +#include + +namespace opendspx { + + struct DynamicMixingAnchor { + int pos{0}; + SourceMixingRatio ratio; + }; + +} + +#endif //OPENDSPX_MODEL_DYNAMICMIXINGANCHOR_H diff --git a/include/opendspx/global.h b/include/opendspx/global.h index 3606e7d..dc0103f 100644 --- a/include/opendspx/global.h +++ b/include/opendspx/global.h @@ -1,16 +1,16 @@ #ifndef OPENDSPX_MODEL_GLOBAL_H #define OPENDSPX_MODEL_GLOBAL_H -#include +#include -namespace QDspx { +namespace opendspx { struct Global { - QString author; - QString name; + std::string author; + std::string name; int centShift{0}; - QString editorId; - QString editorName; + std::string editorId; + std::string editorName; }; } diff --git a/include/opendspx/label.h b/include/opendspx/label.h index 17746e8..bbdd95a 100644 --- a/include/opendspx/label.h +++ b/include/opendspx/label.h @@ -1,13 +1,13 @@ #ifndef OPENDSPX_MODEL_LABEL_H #define OPENDSPX_MODEL_LABEL_H -#include +#include -namespace QDspx { +namespace opendspx { struct Label { int pos{0}; - QString text; + std::string text; }; } diff --git a/include/opendspx/master.h b/include/opendspx/master.h index eb3e404..19eb022 100644 --- a/include/opendspx/master.h +++ b/include/opendspx/master.h @@ -3,7 +3,7 @@ #include -namespace QDspx{ +namespace opendspx{ struct Master { BusControl control; diff --git a/include/opendspx/mixedsinger.h b/include/opendspx/mixedsinger.h new file mode 100644 index 0000000..a2f89a1 --- /dev/null +++ b/include/opendspx/mixedsinger.h @@ -0,0 +1,25 @@ +#ifndef OPENDSPX_MODEL_MIXEDSINGER_H +#define OPENDSPX_MODEL_MIXEDSINGER_H + +#include +#include + +#include +#include + +namespace opendspx { + + struct MixedSinger : Singer { + MixedSinger(std::vector singers = {}, SourceMixingRatio ratio = {}, nlohmann::json extra = {}, Workspace workspace = {}) + : Singer(Type::Mixed, std::move(extra), std::move(workspace)), singers(std::move(singers)), ratio(std::move(ratio)) { + } + + std::vector singers; + SourceMixingRatio ratio; + }; + + using MixedSingerRef = std::shared_ptr; + +} + +#endif //OPENDSPX_MODEL_MIXEDSINGER_H diff --git a/include/opendspx/model.h b/include/opendspx/model.h index c447ef0..c6a908c 100644 --- a/include/opendspx/model.h +++ b/include/opendspx/model.h @@ -3,13 +3,13 @@ #include -namespace QDspx { +namespace opendspx { struct Model { - enum Version { + enum class Version { V1, }; - Version version{V1}; + Version version{Version::V1}; Content content; }; diff --git a/include/opendspx/note.h b/include/opendspx/note.h index 78ddb4b..cb697cf 100644 --- a/include/opendspx/note.h +++ b/include/opendspx/note.h @@ -1,22 +1,22 @@ #ifndef OPENDSPX_MODEL_NOTE_H #define OPENDSPX_MODEL_NOTE_H -#include +#include #include #include #include #include -namespace QDspx { +namespace opendspx { struct Note { int pos{0}; int length{0}; int keyNum{0}; int centShift{0}; - QString language; - QString lyric; + std::string language; + std::string lyric; Pronunciation pronunciation; Phonemes phonemes; Vibrato vibrato; diff --git a/include/opendspx/param.h b/include/opendspx/param.h index c079b0d..b1af284 100644 --- a/include/opendspx/param.h +++ b/include/opendspx/param.h @@ -1,18 +1,18 @@ #ifndef OPENDSPX_MODEL_PARAM_H #define OPENDSPX_MODEL_PARAM_H -#include +#include #include #include #include -namespace QDspx { +namespace opendspx { struct Param { - QList original; - QList transform; - QList edited; + std::vector original; + std::vector transform; + std::vector edited; }; } diff --git a/include/opendspx/paramcurve.h b/include/opendspx/paramcurve.h index 3ebad2d..2339164 100644 --- a/include/opendspx/paramcurve.h +++ b/include/opendspx/paramcurve.h @@ -1,9 +1,9 @@ #ifndef OPENDSPX_MODEL_PARAMCURVE_H #define OPENDSPX_MODEL_PARAMCURVE_H -#include +#include -namespace QDspx { +namespace opendspx { struct ParamCurve { enum Type { @@ -19,7 +19,7 @@ namespace QDspx { } }; - using ParamCurveRef = QSharedPointer; + using ParamCurveRef = std::shared_ptr; } diff --git a/include/opendspx/paramcurveanchor.h b/include/opendspx/paramcurveanchor.h index 74c59c4..3dd32e0 100644 --- a/include/opendspx/paramcurveanchor.h +++ b/include/opendspx/paramcurveanchor.h @@ -1,22 +1,23 @@ #ifndef OPENDSPX_MODEL_PARAMCURVEANCHOR_H #define OPENDSPX_MODEL_PARAMCURVEANCHOR_H -#include +#include +#include #include #include -namespace QDspx { +namespace opendspx { struct ParamCurveAnchor : ParamCurve { - ParamCurveAnchor(int start = 0, const QList &nodes = {}) - : ParamCurve(Anchor, start), nodes(nodes) { + ParamCurveAnchor(int start = 0, std::vector nodes = {}) + : ParamCurve(Anchor, start), nodes(std::move(nodes)) { } - QList nodes; + std::vector nodes; }; - using ParamCurveAnchorRef = QSharedPointer; + using ParamCurveAnchorRef = std::shared_ptr; } diff --git a/include/opendspx/paramcurvefree.h b/include/opendspx/paramcurvefree.h index dd09867..2d108c5 100644 --- a/include/opendspx/paramcurvefree.h +++ b/include/opendspx/paramcurvefree.h @@ -1,22 +1,23 @@ #ifndef OPENDSPX_MODEL_PARAMCURVEFREE_H #define OPENDSPX_MODEL_PARAMCURVEFREE_H -#include +#include +#include #include -namespace QDspx { +namespace opendspx { struct ParamCurveFree : ParamCurve { - ParamCurveFree(int start = 0, int step = 5, const QList &values = {}) - : ParamCurve(Free, start), step(step), values(values) { + ParamCurveFree(int start = 0, int step = 5, std::vector values = {}) + : ParamCurve(Free, start), step(step), values(std::move(values)) { } int step; - QList values; + std::vector values; }; - using ParamCurveFreeRef = QSharedPointer; + using ParamCurveFreeRef = std::shared_ptr; } diff --git a/include/opendspx/params.h b/include/opendspx/params.h index 5856ea7..e6d599f 100644 --- a/include/opendspx/params.h +++ b/include/opendspx/params.h @@ -1,14 +1,17 @@ #ifndef OPENDSPX_MODEL_PARAMS_H #define OPENDSPX_MODEL_PARAMS_H -#include -#include +#include +#include #include -namespace QDspx { +namespace opendspx { - using Params = QMap; + class Params : public std::map { + public: + using std::map::map; + }; } diff --git a/include/opendspx/phoneme.h b/include/opendspx/phoneme.h index 8c41dab..dfc86ad 100644 --- a/include/opendspx/phoneme.h +++ b/include/opendspx/phoneme.h @@ -1,13 +1,13 @@ #ifndef OPENDSPX_MODEL_PHONEME_H #define OPENDSPX_MODEL_PHONEME_H -#include +#include -namespace QDspx { +namespace opendspx { struct Phoneme { - QString language; - QString token; + std::string language; + std::string token; int start{0}; bool onset{false}; }; diff --git a/include/opendspx/phonemes.h b/include/opendspx/phonemes.h index 721a64a..1484c9d 100644 --- a/include/opendspx/phonemes.h +++ b/include/opendspx/phonemes.h @@ -1,15 +1,15 @@ #ifndef OPENDSPX_MODEL_PHONEMES_H #define OPENDSPX_MODEL_PHONEMES_H -#include +#include #include -namespace QDspx { +namespace opendspx { struct Phonemes { - QList original; - QList edited; + std::vector original; + std::vector edited; }; } diff --git a/include/opendspx/pronunciation.h b/include/opendspx/pronunciation.h index 8f49469..c4c5723 100644 --- a/include/opendspx/pronunciation.h +++ b/include/opendspx/pronunciation.h @@ -1,13 +1,13 @@ #ifndef OPENDSPX_MODEL_PRONUNCIATION_H #define OPENDSPX_MODEL_PRONUNCIATION_H -#include +#include -namespace QDspx { +namespace opendspx { struct Pronunciation { - QString original; - QString edited; + std::string original; + std::string edited; }; } diff --git a/include/opendspx/singer.h b/include/opendspx/singer.h new file mode 100644 index 0000000..75b1fcd --- /dev/null +++ b/include/opendspx/singer.h @@ -0,0 +1,32 @@ +#ifndef OPENDSPX_MODEL_SINGER_H +#define OPENDSPX_MODEL_SINGER_H + +#include +#include + +#include + +#include + +namespace opendspx { + + struct Singer { + enum class Type { + Single, + Mixed, + }; + Type type; + nlohmann::json extra; + Workspace workspace; + + protected: + Singer(Type type, nlohmann::json extra = {}, Workspace workspace = {}) + : type(type), extra(std::move(extra)), workspace(std::move(workspace)) { + } + }; + + using SingerRef = std::shared_ptr; + +} + +#endif //OPENDSPX_MODEL_SINGER_H diff --git a/include/opendspx/singingclip.h b/include/opendspx/singingclip.h index e220532..3d308f6 100644 --- a/include/opendspx/singingclip.h +++ b/include/opendspx/singingclip.h @@ -1,26 +1,28 @@ #ifndef OPENDSPX_MODEL_SINGINGCLIP_H #define OPENDSPX_MODEL_SINGINGCLIP_H -#include +#include +#include +#include #include #include #include #include -namespace QDspx { +namespace opendspx { struct SingingClip : Clip { - SingingClip(const QString &name = {}, const BusControl &control = {}, const ClipTime &time = {}, const Workspace &workspace = {}, const QList ¬es = {}, const Params ¶ms = {}, const Sources &sources = {}) - : Clip(Singing, name, control, time, workspace), notes(notes), params(params), sources(sources) { + SingingClip(const std::string &name = {}, const BusControl &control = {}, const ClipTime &time = {}, const Workspace &workspace = {}, std::vector notes = {}, const Params ¶ms = {}, std::optional sources = {}) + : Clip(Type::Singing, name, control, time, workspace), notes(std::move(notes)), params(params), sources(std::move(sources)) { } - QList notes; + std::vector notes; Params params; - Sources sources; + std::optional sources; }; - using SingingClipRef = QSharedPointer; + using SingingClipRef = std::shared_ptr; } diff --git a/include/opendspx/singlesinger.h b/include/opendspx/singlesinger.h new file mode 100644 index 0000000..6f1f956 --- /dev/null +++ b/include/opendspx/singlesinger.h @@ -0,0 +1,23 @@ +#ifndef OPENDSPX_MODEL_SINGLESINGER_H +#define OPENDSPX_MODEL_SINGLESINGER_H + +#include +#include + +#include + +namespace opendspx { + + struct SingleSinger : Singer { + SingleSinger(std::string id = {}, nlohmann::json extra = {}, Workspace workspace = {}) + : Singer(Type::Single, std::move(extra), std::move(workspace)), id(std::move(id)) { + } + + std::string id; + }; + + using SingleSingerRef = std::shared_ptr; + +} + +#endif //OPENDSPX_MODEL_SINGLESINGER_H diff --git a/include/opendspx/sourcemixingratio.h b/include/opendspx/sourcemixingratio.h new file mode 100644 index 0000000..ba46bea --- /dev/null +++ b/include/opendspx/sourcemixingratio.h @@ -0,0 +1,20 @@ +#ifndef OPENDSPX_MODEL_SOURCEMIXINGRATIO_H +#define OPENDSPX_MODEL_SOURCEMIXINGRATIO_H + +#include +#include + +namespace opendspx { + + class SourceMixingRatio : public std::vector { + public: + using std::vector::vector; + + [[nodiscard]] constexpr bool valid() const { + return std::ranges::all_of(*this, [](double x) { return x >= 0 && x <= 1; }) && std::reduce(begin(), end(), 0.0) <= 1.0; + } + }; + +} + +#endif //OPENDSPX_MODEL_SOURCEMIXINGRATIO_H diff --git a/include/opendspx/sources.h b/include/opendspx/sources.h index a675e06..ad64820 100644 --- a/include/opendspx/sources.h +++ b/include/opendspx/sources.h @@ -1,13 +1,21 @@ #ifndef OPENDSPX_MODEL_SOURCES_H #define OPENDSPX_MODEL_SOURCES_H -#include -#include -#include +#include +#include -namespace QDspx { +#include +#include +#include +#include - using Sources = QMap; +namespace opendspx { + + struct Sources { + std::string category; + std::vector mix; + std::vector singers; + }; } diff --git a/include/opendspx/tempo.h b/include/opendspx/tempo.h index c2fb3da..9de0fdc 100644 --- a/include/opendspx/tempo.h +++ b/include/opendspx/tempo.h @@ -1,7 +1,7 @@ #ifndef OPENDSPX_MODEL_TEMPO_H #define OPENDSPX_MODEL_TEMPO_H -namespace QDspx { +namespace opendspx { struct Tempo { int pos{0}; diff --git a/include/opendspx/timeline.h b/include/opendspx/timeline.h index c176ea9..8ad4307 100644 --- a/include/opendspx/timeline.h +++ b/include/opendspx/timeline.h @@ -1,18 +1,18 @@ #ifndef OPENDSPX_MODEL_TIMELINE_H #define OPENDSPX_MODEL_TIMELINE_H -#include +#include #include #include #include -namespace QDspx { +namespace opendspx { struct Timeline { - QList