Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 44 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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})
Expand All @@ -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
Expand All @@ -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
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
)

# Link libraries
target_link_libraries(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE nlohmann_json::nlohmann_json)

if (OPENDSPX_INSTALL)
target_include_directories(${OPENDSPX_INTERPOLATOR_TARGET} INTERFACE
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)

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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
158 changes: 141 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)

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 <opendspxinterpolator/interpolator.h>

using opendspx::Interpolator;

int main() {
auto curve = Interpolator<double>::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 <fstream>
#include <opendspx/model.h>
#include <opendspxserializer/serializer.h>

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 <fstream>
#include <opendspxconverter/midi/midiconverter.h>

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).

Loading