From ba93066396bced2c761577f109b181cc6a8cf8da Mon Sep 17 00:00:00 2001 From: trinitou Date: Mon, 10 Jul 2023 23:58:28 +0200 Subject: [PATCH] initial c++ glue class generator --- include/Application.h | 14 + include/Arrangement.h | 33 ++ include/AuPlugin.h | 13 + include/Audio.h | 16 + include/AutomationTarget.h | 18 + include/BoolParameter.h | 15 + include/BoolPoint.h | 14 + include/BuiltinDevice.h | 13 + include/Channel.h | 29 ++ include/ClapPlugin.h | 13 + include/Clip.h | 26 ++ include/ClipSlot.h | 16 + include/Clips.h | 15 + include/Compressor.h | 22 + include/Device.h | 22 + include/EnumParameter.h | 18 + include/EnumPoint.h | 14 + include/EqBand.h | 19 + include/Equalizer.h | 18 + include/FileReference.h | 19 + include/IntegerParameter.h | 17 + include/IntegerPoint.h | 14 + include/Lane.h | 11 + include/Lanes.h | 14 + include/Limiter.h | 19 + include/Marker.h | 14 + include/Markers.h | 15 + include/MediaFile.h | 16 + include/MetaData.h | 25 ++ include/Nameable.h | 15 + include/NoiseGate.h | 19 + include/Note.h | 19 + include/Notes.h | 15 + include/Parameter.h | 14 + include/Plugin.h | 14 + include/Point.h | 12 + include/Points.h | 18 + include/Project.h | 26 ++ include/RealParameter.h | 22 + include/RealPoint.h | 15 + include/Scene.h | 27 ++ include/Send.h | 19 + include/TimeSignatureParameter.h | 18 + include/TimeSignaturePoint.h | 15 + include/Timeline.h | 15 + include/Track.h | 21 + include/Transport.h | 17 + include/Video.h | 16 + include/Vst2Plugin.h | 13 + include/Vst3Plugin.h | 13 + include/Warp.h | 13 + include/Warps.h | 17 + include/common.h | 97 +++++ .../bitwig/dawproject/GenerateCppTest.java | 391 ++++++++++++++++++ 54 files changed, 1393 insertions(+) create mode 100644 include/Application.h create mode 100644 include/Arrangement.h create mode 100644 include/AuPlugin.h create mode 100644 include/Audio.h create mode 100644 include/AutomationTarget.h create mode 100644 include/BoolParameter.h create mode 100644 include/BoolPoint.h create mode 100644 include/BuiltinDevice.h create mode 100644 include/Channel.h create mode 100644 include/ClapPlugin.h create mode 100644 include/Clip.h create mode 100644 include/ClipSlot.h create mode 100644 include/Clips.h create mode 100644 include/Compressor.h create mode 100644 include/Device.h create mode 100644 include/EnumParameter.h create mode 100644 include/EnumPoint.h create mode 100644 include/EqBand.h create mode 100644 include/Equalizer.h create mode 100644 include/FileReference.h create mode 100644 include/IntegerParameter.h create mode 100644 include/IntegerPoint.h create mode 100644 include/Lane.h create mode 100644 include/Lanes.h create mode 100644 include/Limiter.h create mode 100644 include/Marker.h create mode 100644 include/Markers.h create mode 100644 include/MediaFile.h create mode 100644 include/MetaData.h create mode 100644 include/Nameable.h create mode 100644 include/NoiseGate.h create mode 100644 include/Note.h create mode 100644 include/Notes.h create mode 100644 include/Parameter.h create mode 100644 include/Plugin.h create mode 100644 include/Point.h create mode 100644 include/Points.h create mode 100644 include/Project.h create mode 100644 include/RealParameter.h create mode 100644 include/RealPoint.h create mode 100644 include/Scene.h create mode 100644 include/Send.h create mode 100644 include/TimeSignatureParameter.h create mode 100644 include/TimeSignaturePoint.h create mode 100644 include/Timeline.h create mode 100644 include/Track.h create mode 100644 include/Transport.h create mode 100644 include/Video.h create mode 100644 include/Vst2Plugin.h create mode 100644 include/Vst3Plugin.h create mode 100644 include/Warp.h create mode 100644 include/Warps.h create mode 100644 include/common.h create mode 100644 src/test/java/com/bitwig/dawproject/GenerateCppTest.java diff --git a/include/Application.h b/include/Application.h new file mode 100644 index 0000000..b3a0622 --- /dev/null +++ b/include/Application.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +/* Metadata about the application which saved the DAWPROJECT file. */ +struct Application +{ + std::string name; // Name of the application. + std::string version; // Version number of the application. +}; +} // namespace DawProject + diff --git a/include/Arrangement.h b/include/Arrangement.h new file mode 100644 index 0000000..814a308 --- /dev/null +++ b/include/Arrangement.h @@ -0,0 +1,33 @@ +#pragma once + +#include "common.h" +#include "Lanes.h" +#include "Markers.h" +#include "Points.h" + +namespace DawProject +{ +/* Represents the main Arrangement timeline of a DAW. */ +struct Arrangement +{ + /* Automation data for time-signature inside this Arrangement. +

+     <Arrangement>
+       <TimeSignatureAutomation target="id-of-TimeSignatureParameter" ... >
+         <TimeSignaturePoint time="0" numerator="7", denominator="8"/>
+         <TimeSignaturePoint time="21" numerator="4", denominator="4"/>
+            ...
+       </TimeSignatureAutomation>
+     </Arrangement>
+     
*/ + std::optional timeSignatureAutomation; + /* Automation data for tempo inside this Arrangement, which will define the conversion between seconds and beats + at the root level. */ + std::optional tempoAutomation; + std::optional markers; // Cue markers inside this arrangement + /* The lanes of this arrangement. Generally this would contain another Lanes timeline for (and scoped to) each + track which would then contain all Note, Audio, and Automation timelines. */ + std::optional lanes; +}; +} // namespace DawProject + diff --git a/include/AuPlugin.h b/include/AuPlugin.h new file mode 100644 index 0000000..471e52d --- /dev/null +++ b/include/AuPlugin.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common.h" +#include "Plugin.h" + +namespace DawProject +{ +struct AuPlugin + : public Plugin +{ +}; +} // namespace DawProject + diff --git a/include/Audio.h b/include/Audio.h new file mode 100644 index 0000000..d14eeb6 --- /dev/null +++ b/include/Audio.h @@ -0,0 +1,16 @@ +#pragma once + +#include "common.h" +#include "MediaFile.h" + +namespace DawProject +{ +struct Audio + : public MediaFile +{ + int sampleRate; + int channels; + std::optional algorithm; +}; +} // namespace DawProject + diff --git a/include/AutomationTarget.h b/include/AutomationTarget.h new file mode 100644 index 0000000..4831eea --- /dev/null +++ b/include/AutomationTarget.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +struct Parameter; + +struct AutomationTarget +{ + Parameter* parameter; + std::optional expression; + std::optional channel; + std::optional key; + std::optional controller; +}; +} // namespace DawProject + diff --git a/include/BoolParameter.h b/include/BoolParameter.h new file mode 100644 index 0000000..4f371f2 --- /dev/null +++ b/include/BoolParameter.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" +#include "Parameter.h" + +namespace DawProject +{ +/* Represents a parameter which can provide a boolean (true/false) value and be used as an automation target. */ +struct BoolParameter + : public Parameter +{ + std::optional value; // Boolean value for this parameter. +}; +} // namespace DawProject + diff --git a/include/BoolPoint.h b/include/BoolPoint.h new file mode 100644 index 0000000..e4f0502 --- /dev/null +++ b/include/BoolPoint.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" +#include "Point.h" + +namespace DawProject +{ +struct BoolPoint + : public Point +{ + bool value; +}; +} // namespace DawProject + diff --git a/include/BuiltinDevice.h b/include/BuiltinDevice.h new file mode 100644 index 0000000..edf21e4 --- /dev/null +++ b/include/BuiltinDevice.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common.h" +#include "Device.h" + +namespace DawProject +{ +struct BuiltinDevice + : public Device +{ +}; +} // namespace DawProject + diff --git a/include/Channel.h b/include/Channel.h new file mode 100644 index 0000000..01d7887 --- /dev/null +++ b/include/Channel.h @@ -0,0 +1,29 @@ +#pragma once + +#include "common.h" +#include "Lane.h" +#include "Send.h" +#include "BoolParameter.h" +#include "RealParameter.h" +#include "Device.h" + +namespace DawProject +{ +/* Represents a mixer channel. It provides the ability to route signals to other channels and can contain + Device/Plug-in for processing. */ +struct Channel + : public Lane +{ + std::optional role; // Role of this channel in the mixer. + /* Number of audio-channels of this mixer channel. (1=mono, 2=stereo…) */ + std::optional audioChannels; + std::optional volume; // Channel volume + std::optional pan; // Channel pan/balance + std::optional mute; // Channel mute + std::optional solo; // Channel solo + Channel* destination; // Output channel routing + std::vector sends; // Send levels & destination + std::vector devices; // Devices & plug-ins of this channel +}; +} // namespace DawProject + diff --git a/include/ClapPlugin.h b/include/ClapPlugin.h new file mode 100644 index 0000000..a8af47e --- /dev/null +++ b/include/ClapPlugin.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common.h" +#include "Plugin.h" + +namespace DawProject +{ +struct ClapPlugin + : public Plugin +{ +}; +} // namespace DawProject + diff --git a/include/Clip.h b/include/Clip.h new file mode 100644 index 0000000..4a4ddd1 --- /dev/null +++ b/include/Clip.h @@ -0,0 +1,26 @@ +#pragma once + +#include "common.h" +#include "Nameable.h" +#include "Timeline.h" + +namespace DawProject +{ +struct Clip + : public Nameable +{ + double time; + std::optional duration; + std::optional contentTimeUnit; + std::optional playStart; + std::optional playStop; + std::optional loopStart; + std::optional loopEnd; + std::optional fadeTimeUnit; + std::optional fadeInTime; + std::optional fadeOutTime; + std::optional content; + Timeline* reference; +}; +} // namespace DawProject + diff --git a/include/ClipSlot.h b/include/ClipSlot.h new file mode 100644 index 0000000..7b606d3 --- /dev/null +++ b/include/ClipSlot.h @@ -0,0 +1,16 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "Clip.h" + +namespace DawProject +{ +struct ClipSlot + : public Timeline +{ + std::optional hasStop; + std::optional clip; +}; +} // namespace DawProject + diff --git a/include/Clips.h b/include/Clips.h new file mode 100644 index 0000000..af61b9e --- /dev/null +++ b/include/Clips.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "Clip.h" + +namespace DawProject +{ +struct Clips + : public Timeline +{ + std::vector clips; +}; +} // namespace DawProject + diff --git a/include/Compressor.h b/include/Compressor.h new file mode 100644 index 0000000..83a0e66 --- /dev/null +++ b/include/Compressor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "common.h" +#include "BuiltinDevice.h" +#include "BoolParameter.h" +#include "RealParameter.h" + +namespace DawProject +{ +struct Compressor + : public BuiltinDevice +{ + std::optional threshold; + std::optional ratio; + std::optional attack; + std::optional release; + std::optional inputGain; + std::optional outputGain; + std::optional autoMakeup; +}; +} // namespace DawProject + diff --git a/include/Device.h b/include/Device.h new file mode 100644 index 0000000..5835ef1 --- /dev/null +++ b/include/Device.h @@ -0,0 +1,22 @@ +#pragma once + +#include "common.h" +#include "FileReference.h" +#include "Parameter.h" +#include "BoolParameter.h" + +namespace DawProject +{ +struct Device +{ + std::optional enabled; + DeviceRole deviceRole; + std::optional loaded; + std::string deviceName; + std::optional deviceID; + std::optional deviceVendor; + std::optional state; + std::vector automatedParameters; +}; +} // namespace DawProject + diff --git a/include/EnumParameter.h b/include/EnumParameter.h new file mode 100644 index 0000000..d8cb462 --- /dev/null +++ b/include/EnumParameter.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" +#include "Parameter.h" + +namespace DawProject +{ +/* Represents an enumerated parameter which can provide a value and be used as an automation target. */ +struct EnumParameter + : public Parameter +{ + std::optional value; // Index of the enum value. + /* Number of entries in enum value. value will be in the range [0 .. count-1]. */ + int count; + std::vector labels; // Labels of the individual enum values. +}; +} // namespace DawProject + diff --git a/include/EnumPoint.h b/include/EnumPoint.h new file mode 100644 index 0000000..ae5d028 --- /dev/null +++ b/include/EnumPoint.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" +#include "Point.h" + +namespace DawProject +{ +struct EnumPoint + : public Point +{ + int value; +}; +} // namespace DawProject + diff --git a/include/EqBand.h b/include/EqBand.h new file mode 100644 index 0000000..8fbed96 --- /dev/null +++ b/include/EqBand.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common.h" +#include "BoolParameter.h" +#include "RealParameter.h" + +namespace DawProject +{ +struct EqBand +{ + RealParameter freq; + std::optional gain; + std::optional Q; + std::optional enabled; + EqBandType type; + std::optional order; +}; +} // namespace DawProject + diff --git a/include/Equalizer.h b/include/Equalizer.h new file mode 100644 index 0000000..dc06d31 --- /dev/null +++ b/include/Equalizer.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" +#include "BuiltinDevice.h" +#include "RealParameter.h" +#include "EqBand.h" + +namespace DawProject +{ +struct Equalizer + : public BuiltinDevice +{ + std::vector bands; + std::optional inputGain; + std::optional outputGain; +}; +} // namespace DawProject + diff --git a/include/FileReference.h b/include/FileReference.h new file mode 100644 index 0000000..bafc5c7 --- /dev/null +++ b/include/FileReference.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +/* References a file either within a DAWPROJECT container or on disk. */ +struct FileReference +{ + /* File path. either +
  • path within the container
  • +
  • relative to .dawproject file (when external = "true")
  • +
  • absolute path (when external = "true" and path starts with a slash or windows drive letter)
  • */ + std::string path; + /* When true, the path is relative to the .dawproject file. Default value is false. */ + std::optional external; +}; +} // namespace DawProject + diff --git a/include/IntegerParameter.h b/include/IntegerParameter.h new file mode 100644 index 0000000..7dfca9e --- /dev/null +++ b/include/IntegerParameter.h @@ -0,0 +1,17 @@ +#pragma once + +#include "common.h" +#include "Parameter.h" + +namespace DawProject +{ +/* Represents an enumerated parameter which can provide a value and be used as an automation target. */ +struct IntegerParameter + : public Parameter +{ + std::optional value; // Integer value for this parameter. + std::optional min; // Minimum value this parameter can have (inclusive). + std::optional max; // Maximum value this parameter can have (inclusive). +}; +} // namespace DawProject + diff --git a/include/IntegerPoint.h b/include/IntegerPoint.h new file mode 100644 index 0000000..c061dd4 --- /dev/null +++ b/include/IntegerPoint.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" +#include "Point.h" + +namespace DawProject +{ +struct IntegerPoint + : public Point +{ + int value; +}; +} // namespace DawProject + diff --git a/include/Lane.h b/include/Lane.h new file mode 100644 index 0000000..c3a7d55 --- /dev/null +++ b/include/Lane.h @@ -0,0 +1,11 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +struct Lane +{ +}; +} // namespace DawProject + diff --git a/include/Lanes.h b/include/Lanes.h new file mode 100644 index 0000000..68973b8 --- /dev/null +++ b/include/Lanes.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" + +namespace DawProject +{ +struct Lanes + : public Timeline +{ + std::vector lanes; +}; +} // namespace DawProject + diff --git a/include/Limiter.h b/include/Limiter.h new file mode 100644 index 0000000..d159acd --- /dev/null +++ b/include/Limiter.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common.h" +#include "BuiltinDevice.h" +#include "RealParameter.h" + +namespace DawProject +{ +struct Limiter + : public BuiltinDevice +{ + std::optional threshold; + std::optional inputGain; + std::optional outputGain; + std::optional attack; + std::optional release; +}; +} // namespace DawProject + diff --git a/include/Marker.h b/include/Marker.h new file mode 100644 index 0000000..d895831 --- /dev/null +++ b/include/Marker.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" +#include "Nameable.h" + +namespace DawProject +{ +struct Marker + : public Nameable +{ + double time; +}; +} // namespace DawProject + diff --git a/include/Markers.h b/include/Markers.h new file mode 100644 index 0000000..be05a6d --- /dev/null +++ b/include/Markers.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "Marker.h" + +namespace DawProject +{ +struct Markers + : public Timeline +{ + std::vector markers; +}; +} // namespace DawProject + diff --git a/include/MediaFile.h b/include/MediaFile.h new file mode 100644 index 0000000..824b1e9 --- /dev/null +++ b/include/MediaFile.h @@ -0,0 +1,16 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "FileReference.h" + +namespace DawProject +{ +struct MediaFile + : public Timeline +{ + FileReference file; + double duration; +}; +} // namespace DawProject + diff --git a/include/MetaData.h b/include/MetaData.h new file mode 100644 index 0000000..0890cd5 --- /dev/null +++ b/include/MetaData.h @@ -0,0 +1,25 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +/* Metadata root element of the DAWPROJECT format. This is stored in the file metadata.xml file inside the container. */ +struct MetaData +{ + std::optional title; // Title of the song/project. + std::optional artist; // Recording Artist. + std::optional album; // Album. + std::optional originalArtist; // Original Artist. + std::optional composer; // Composer. + std::optional songwriter; // Songwriter. + std::optional producer; // Producer. + std::optional arranger; // Arranger. + std::optional year; // Year this project/song was recorded. + std::optional genre; // Genre/style + std::optional copyright; // Copyright notice. + std::optional website; // URL to website related to this project. + std::optional comment; // General comment or description. +}; +} // namespace DawProject + diff --git a/include/Nameable.h b/include/Nameable.h new file mode 100644 index 0000000..c0663cd --- /dev/null +++ b/include/Nameable.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +struct Nameable +{ + std::optional name; // Name/label of this object. + /* Color of this object in HTML-style format. (#rrggbb) */ + std::optional color; + std::optional comment; // Comment/description of this object. +}; +} // namespace DawProject + diff --git a/include/NoiseGate.h b/include/NoiseGate.h new file mode 100644 index 0000000..d164b5e --- /dev/null +++ b/include/NoiseGate.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common.h" +#include "BuiltinDevice.h" +#include "RealParameter.h" + +namespace DawProject +{ +struct NoiseGate + : public BuiltinDevice +{ + std::optional threshold; + std::optional ratio; + std::optional attack; + std::optional release; + std::optional range; +}; +} // namespace DawProject + diff --git a/include/Note.h b/include/Note.h new file mode 100644 index 0000000..60a6a2d --- /dev/null +++ b/include/Note.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" + +namespace DawProject +{ +struct Note +{ + double time; + double duration; + std::optional channel; + int key; + std::optional velocity; + std::optional releaseVelocity; + std::optional content; +}; +} // namespace DawProject + diff --git a/include/Notes.h b/include/Notes.h new file mode 100644 index 0000000..67dfd91 --- /dev/null +++ b/include/Notes.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "Note.h" + +namespace DawProject +{ +struct Notes + : public Timeline +{ + std::vector notes; +}; +} // namespace DawProject + diff --git a/include/Parameter.h b/include/Parameter.h new file mode 100644 index 0000000..379c32f --- /dev/null +++ b/include/Parameter.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +/* Represents a parameter which can provide a value and be used as an automation target. */ +struct Parameter +{ + /* Parameter ID as used by VST2 (index), VST3(ParamID) */ + std::optional parameterID; +}; +} // namespace DawProject + diff --git a/include/Plugin.h b/include/Plugin.h new file mode 100644 index 0000000..1f177aa --- /dev/null +++ b/include/Plugin.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common.h" +#include "Device.h" + +namespace DawProject +{ +struct Plugin + : public Device +{ + std::optional pluginVersion; +}; +} // namespace DawProject + diff --git a/include/Point.h b/include/Point.h new file mode 100644 index 0000000..193c61d --- /dev/null +++ b/include/Point.h @@ -0,0 +1,12 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +struct Point +{ + double time; +}; +} // namespace DawProject + diff --git a/include/Points.h b/include/Points.h new file mode 100644 index 0000000..884b2fc --- /dev/null +++ b/include/Points.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "AutomationTarget.h" +#include "Point.h" + +namespace DawProject +{ +struct Points + : public Timeline +{ + AutomationTarget target; + std::vector points; + std::optional unit; +}; +} // namespace DawProject + diff --git a/include/Project.h b/include/Project.h new file mode 100644 index 0000000..ace5723 --- /dev/null +++ b/include/Project.h @@ -0,0 +1,26 @@ +#pragma once + +#include "common.h" +#include "Application.h" +#include "Transport.h" +#include "Lane.h" +#include "Arrangement.h" +#include "Scene.h" + +namespace DawProject +{ +/* The main root element of the DAWPROJECT format. This is stored in the file project.xml file inside the container. */ +struct Project +{ + /* Version of DAWPROJECT format this file was saved as. */ + std::string version; + /* Metadata (name/version) about the application that saved this file. */ + Application application; + /* Transport element containing playback parameters such as Tempo and Time-signature. */ + std::optional transport; + std::vector structure; // Track/Channel structure of this file. + std::optional arrangement; // The main Arrangement timeline of this file. + std::vector scenes; // Clip Launcher scenes of this file. +}; +} // namespace DawProject + diff --git a/include/RealParameter.h b/include/RealParameter.h new file mode 100644 index 0000000..fcdcf06 --- /dev/null +++ b/include/RealParameter.h @@ -0,0 +1,22 @@ +#pragma once + +#include "common.h" +#include "Parameter.h" + +namespace DawProject +{ +/* Represents a real valued (double) parameter which can provide a value and be used as an automation target. */ +struct RealParameter + : public Parameter +{ + /* Real (double) value for this parameter. +

    When serializing value to text for XML, infinite values are allowed and should be represented as inf and -inf.

    */ + std::optional value; + /* Unit in which value, min and max are defined. +

    Using this rather than normalized value ranges allows transfer of parameter values and automation data.

    */ + Unit unit; + std::optional min; // Minimum value this parameter can have (inclusive). + std::optional max; // Maximum value this parameter can have (inclusive). +}; +} // namespace DawProject + diff --git a/include/RealPoint.h b/include/RealPoint.h new file mode 100644 index 0000000..b75beae --- /dev/null +++ b/include/RealPoint.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" +#include "Point.h" + +namespace DawProject +{ +struct RealPoint + : public Point +{ + double value; + std::optional interpolation; +}; +} // namespace DawProject + diff --git a/include/Scene.h b/include/Scene.h new file mode 100644 index 0000000..5abd77c --- /dev/null +++ b/include/Scene.h @@ -0,0 +1,27 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" + +namespace DawProject +{ +/* Represents a clip launcher Scene of a DAW. */ +struct Scene +{ + /* Content timeline of this scene, will typically be structured like this: +
    
    +     <Scene>
    +       <Lanes>
    +         <ClipSlot track="...">
    +            <Clip>
    +               ...
    +            </Clip>
    +         </ClipSlot>
    +          ...
    +       </Lanes>
    +     </Scene>
    +     
    */ + Timeline content; +}; +} // namespace DawProject + diff --git a/include/Send.h b/include/Send.h new file mode 100644 index 0000000..272aac5 --- /dev/null +++ b/include/Send.h @@ -0,0 +1,19 @@ +#pragma once + +#include "common.h" +#include "RealParameter.h" + +namespace DawProject +{ +struct Channel; + +/* A single send of a mixer channel. */ +struct Send +{ + RealParameter volume; // Send level. + std::optional pan; // Send pan/balance. + std::optional type; // Send type. + Channel* destination; // Send destination. +}; +} // namespace DawProject + diff --git a/include/TimeSignatureParameter.h b/include/TimeSignatureParameter.h new file mode 100644 index 0000000..07d76ea --- /dev/null +++ b/include/TimeSignatureParameter.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" +#include "Parameter.h" + +namespace DawProject +{ +/* Represents a (the) time-signature parameter which can provide a value and be used as an automation target. */ +struct TimeSignatureParameter + : public Parameter +{ + /* Numerator of the time-signature. (3/4 → 3, 4/4 → 4) */ + int numerator; + /* Denominator of the time-signature. (3/4 → 4, 7/8 → 8) */ + int denominator; +}; +} // namespace DawProject + diff --git a/include/TimeSignaturePoint.h b/include/TimeSignaturePoint.h new file mode 100644 index 0000000..a25aacd --- /dev/null +++ b/include/TimeSignaturePoint.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" +#include "Point.h" + +namespace DawProject +{ +struct TimeSignaturePoint + : public Point +{ + int numerator; + int denominator; +}; +} // namespace DawProject + diff --git a/include/Timeline.h b/include/Timeline.h new file mode 100644 index 0000000..7011cfc --- /dev/null +++ b/include/Timeline.h @@ -0,0 +1,15 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +struct Track; + +struct Timeline +{ + Track* track; + std::optional timeUnit; +}; +} // namespace DawProject + diff --git a/include/Track.h b/include/Track.h new file mode 100644 index 0000000..a64f0ca --- /dev/null +++ b/include/Track.h @@ -0,0 +1,21 @@ +#pragma once + +#include "common.h" +#include "Lane.h" +#include "Channel.h" + +namespace DawProject +{ +/* Represents a sequencer track. */ +struct Track + : public Lane +{ + /* Role of this track in timelines & arranger. Can be multiple (comma-separated). */ + std::vector contentType; + std::optional loaded; // If this track is loaded/active of not. + std::optional channel; // Mixer channel used for the output of this track. + /* Child tracks, typically used to represent group/folder tracks with contentType="tracks". */ + std::vector tracks; +}; +} // namespace DawProject + diff --git a/include/Transport.h b/include/Transport.h new file mode 100644 index 0000000..bbee38f --- /dev/null +++ b/include/Transport.h @@ -0,0 +1,17 @@ +#pragma once + +#include "common.h" +#include "RealParameter.h" +#include "TimeSignatureParameter.h" + +namespace DawProject +{ +/* Transport element containing playback parameters such as Tempo and Time-signature. */ +struct Transport +{ + /* Tempo parameter for setting and/or automating the tempo. */ + std::optional tempo; + std::optional timeSignature; // Time-signature parameter. +}; +} // namespace DawProject + diff --git a/include/Video.h b/include/Video.h new file mode 100644 index 0000000..c5f0021 --- /dev/null +++ b/include/Video.h @@ -0,0 +1,16 @@ +#pragma once + +#include "common.h" +#include "MediaFile.h" + +namespace DawProject +{ +struct Video + : public MediaFile +{ + std::optional sampleRate; + std::optional channels; + std::optional algorithm; +}; +} // namespace DawProject + diff --git a/include/Vst2Plugin.h b/include/Vst2Plugin.h new file mode 100644 index 0000000..7d7b1bd --- /dev/null +++ b/include/Vst2Plugin.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common.h" +#include "Plugin.h" + +namespace DawProject +{ +struct Vst2Plugin + : public Plugin +{ +}; +} // namespace DawProject + diff --git a/include/Vst3Plugin.h b/include/Vst3Plugin.h new file mode 100644 index 0000000..8c1d0d3 --- /dev/null +++ b/include/Vst3Plugin.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common.h" +#include "Plugin.h" + +namespace DawProject +{ +struct Vst3Plugin + : public Plugin +{ +}; +} // namespace DawProject + diff --git a/include/Warp.h b/include/Warp.h new file mode 100644 index 0000000..10c6630 --- /dev/null +++ b/include/Warp.h @@ -0,0 +1,13 @@ +#pragma once + +#include "common.h" + +namespace DawProject +{ +struct Warp +{ + double time; + double contentTime; +}; +} // namespace DawProject + diff --git a/include/Warps.h b/include/Warps.h new file mode 100644 index 0000000..7e04e3d --- /dev/null +++ b/include/Warps.h @@ -0,0 +1,17 @@ +#pragma once + +#include "common.h" +#include "Timeline.h" +#include "Warp.h" + +namespace DawProject +{ +struct Warps + : public Timeline +{ + std::vector events; + Timeline content; + TimeUnit contentTimeUnit; +}; +} // namespace DawProject + diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..11e8c86 --- /dev/null +++ b/include/common.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include + +namespace DawProject +{ +//constants +static constexpr std::string_view CURRENT_VERSION = "1.0"; + +//enums +enum TimeUnit: int +{ + TIME_UNIT_BEATS = 0, + TIME_UNIT_SECONDS = 1, +}; + +enum Interpolation: int +{ + INTERPOLATION_HOLD = 0, + INTERPOLATION_LINEAR = 1, +}; + +enum Unit: int +{ + UNIT_LINEAR = 0, + UNIT_NORMALIZED = 1, + UNIT_PERCENT = 2, + UNIT_DECIBEL = 3, + UNIT_HERTZ = 4, + UNIT_SEMITONES = 5, + UNIT_SECONDS = 6, + UNIT_BEATS = 7, + UNIT_BPM = 8, +}; + +enum SendType: int +{ + SEND_TYPE_PRE = 0, + SEND_TYPE_POST = 1, +}; + +enum MixerRole: int +{ + MIXER_ROLE_REGULAR = 0, + MIXER_ROLE_MASTER = 1, + MIXER_ROLE_EFFECTTRACK = 2, + MIXER_ROLE_SUBMIX = 3, + MIXER_ROLE_VCA = 4, +}; + +enum DeviceRole: int +{ + DEVICE_ROLE_INSTRUMENT = 0, + DEVICE_ROLE_NOTEFX = 1, + DEVICE_ROLE_AUDIOFX = 2, + DEVICE_ROLE_ANALYZER = 3, +}; + +enum ContentType: int +{ + CONTENT_TYPE_AUDIO = 0, + CONTENT_TYPE_AUTOMATION = 1, + CONTENT_TYPE_NOTES = 2, + CONTENT_TYPE_VIDEO = 3, + CONTENT_TYPE_MARKERS = 4, + CONTENT_TYPE_TRACKS = 5, +}; + +enum ExpressionType: int +{ + EXPRESSION_TYPE_GAIN = 0, + EXPRESSION_TYPE_PAN = 1, + EXPRESSION_TYPE_TRANSPOSE = 2, + EXPRESSION_TYPE_TIMBRE = 3, + EXPRESSION_TYPE_FORMANT = 4, + EXPRESSION_TYPE_PRESSURE = 5, + EXPRESSION_TYPE_CHANNELCONTROLLER = 6, + EXPRESSION_TYPE_CHANNELPRESSURE = 7, + EXPRESSION_TYPE_POLYPRESSURE = 8, + EXPRESSION_TYPE_PITCHBEND = 9, + EXPRESSION_TYPE_PROGRAMCHANGE = 10, +}; + +enum EqBandType: int +{ + EQ_BAND_TYPE_HIGHPASS = 0, + EQ_BAND_TYPE_LOWPASS = 1, + EQ_BAND_TYPE_BANDPASS = 2, + EQ_BAND_TYPE_HIGHSHELF = 3, + EQ_BAND_TYPE_LOWSHELF = 4, + EQ_BAND_TYPE_BELL = 5, + EQ_BAND_TYPE_NOTCH = 6, +}; +} // namespace DawProject + diff --git a/src/test/java/com/bitwig/dawproject/GenerateCppTest.java b/src/test/java/com/bitwig/dawproject/GenerateCppTest.java new file mode 100644 index 0000000..b543452 --- /dev/null +++ b/src/test/java/com/bitwig/dawproject/GenerateCppTest.java @@ -0,0 +1,391 @@ +package com.bitwig.dawproject; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import com.bitwig.dawproject.device.AuPlugin; +import com.bitwig.dawproject.device.BuiltinDevice; +import com.bitwig.dawproject.device.ClapPlugin; +import com.bitwig.dawproject.device.Compressor; +import com.bitwig.dawproject.device.Device; +import com.bitwig.dawproject.device.DeviceRole; +import com.bitwig.dawproject.device.EqBand; +import com.bitwig.dawproject.device.EqBandType; +import com.bitwig.dawproject.device.Equalizer; +import com.bitwig.dawproject.device.Limiter; +import com.bitwig.dawproject.device.NoiseGate; +import com.bitwig.dawproject.device.Plugin; +import com.bitwig.dawproject.device.Vst2Plugin; +import com.bitwig.dawproject.device.Vst3Plugin; +import com.bitwig.dawproject.timeline.Audio; +import com.bitwig.dawproject.timeline.AutomationTarget; +import com.bitwig.dawproject.timeline.BoolPoint; +import com.bitwig.dawproject.timeline.Clip; +import com.bitwig.dawproject.timeline.ClipSlot; +import com.bitwig.dawproject.timeline.Clips; +import com.bitwig.dawproject.timeline.EnumPoint; +import com.bitwig.dawproject.timeline.IntegerPoint; +import com.bitwig.dawproject.timeline.Lanes; +import com.bitwig.dawproject.timeline.Marker; +import com.bitwig.dawproject.timeline.Markers; +import com.bitwig.dawproject.timeline.MediaFile; +import com.bitwig.dawproject.timeline.Note; +import com.bitwig.dawproject.timeline.Notes; +import com.bitwig.dawproject.timeline.Point; +import com.bitwig.dawproject.timeline.Points; +import com.bitwig.dawproject.timeline.RealPoint; +import com.bitwig.dawproject.timeline.TimeSignaturePoint; +import com.bitwig.dawproject.timeline.TimeUnit; +import com.bitwig.dawproject.timeline.Timeline; +import com.bitwig.dawproject.timeline.Video; +import com.bitwig.dawproject.timeline.Warp; +import com.bitwig.dawproject.timeline.Warps; +import com.github.therapi.runtimejavadoc.BaseJavadoc; +import com.github.therapi.runtimejavadoc.CommentFormatter; +import com.github.therapi.runtimejavadoc.FieldJavadoc; +import com.github.therapi.runtimejavadoc.RuntimeJavadoc; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementRef; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlIDREF; +import org.junit.Assert; +import org.junit.Test; + +public class GenerateCppTest +{ + private final static Class[] classes = new Class[] { + // Root + Project.class, MetaData.class, + // Other + Application.class, FileReference.class, Transport.class, + // Mixer + Lane.class, Track.class, Channel.class, Send.class, + // Timeline + Arrangement.class, + Scene.class, + ClipSlot.class, + Timeline.class, + Lanes.class, + Clips.class, + Clip.class, + Notes.class, + Note.class, + Audio.class, + Video.class, + Warps.class, + Warp.class, + Markers.class, + Marker.class, + // Parameters + Parameter.class, + BoolParameter.class, + EnumParameter.class, + IntegerParameter.class, + RealParameter.class, + TimeSignatureParameter.class, + // Automation + Points.class, + AutomationTarget.class, + Point.class, + RealPoint.class, + BoolPoint.class, + EnumPoint.class, + IntegerPoint.class, + TimeSignaturePoint.class, + // Device + Device.class, AuPlugin.class, ClapPlugin.class, Plugin.class, Vst2Plugin.class, Vst3Plugin.class, + BuiltinDevice.class, + Compressor.class, + Equalizer.class, EqBand.class, + Limiter.class, + NoiseGate.class, + // Abstract + Nameable.class,/* Referenceable.class,*/ MediaFile.class, + }; + + private final static Enum[][] enums = new Enum[][] { + TimeUnit.values(), + Interpolation.values(), + Unit.values(), + SendType.values(), + MixerRole.values(), + DeviceRole.values(), + ContentType.values(), + ExpressionType.values(), + EqBandType.values(), + }; + + @Test + public void generateCppFile() throws IOException + { + final var includePath = Paths.get("include"); + if (!Files.exists(includePath)) + Files.createDirectory(includePath); + Assert.assertTrue(Files.isDirectory(includePath)); + final var targetPathString = includePath.toAbsolutePath() + "/"; + + final var sb = new StringBuilder(); + + // generate common header + sb.append("#pragma once\n\n"); + sb.append("#include \n"); + sb.append("#include \n"); + sb.append("#include \n"); + sb.append("\n"); + sb.append("namespace DawProject\n{\n"); + sb.append("//constants\n"); + sb.append("static constexpr std::string_view CURRENT_VERSION = \"" + Project.CURRENT_VERSION + "\";\n\n"); + sb.append("//enums\n"); + generateEnums(sb); + sb.append("} // namespace DawProject\n"); + final var enumHeaderFile = new File(targetPathString + "common.h"); + Files.write(enumHeaderFile.toPath(), Collections.singleton(sb.toString()), StandardCharsets.UTF_8); + Assert.assertTrue(enumHeaderFile.exists()); + + // generate class files + for (final var cls : classes) + { + sb.setLength(0); + sb.append("#pragma once\n\n"); + sb.append("#include \"common.h\"\n"); + final var superclass = cls.getSuperclass(); + if(isRelevantSuperClass(superclass)) + sb.append("#include \"" + superclass.getSimpleName() + ".h\"\n"); + var forwardDeclaredClassNames = new ArrayList(); + for (final var otherClass : classes) + { + if(otherClass == cls) + continue; // don't include itself + if(otherClass == superclass) + continue; // already handled above + for(final var field : cls.getDeclaredFields()) + { + Class fieldType = field.getType(); + if (fieldType.isArray()) + fieldType = fieldType.getComponentType(); + else if(fieldType == List.class) + fieldType = getListGenericType(field); + if(otherClass == fieldType) + { + if(isIdRef(field)) + { + forwardDeclaredClassNames.add(otherClass.getSimpleName()); + continue; + } + else + sb.append("#include \"" + otherClass.getSimpleName() + ".h\"\n"); + break; + } + } + } + sb.append("\n"); + sb.append("namespace DawProject\n{\n"); + for(final var className : forwardDeclaredClassNames) + { + sb.append("struct " + className + ";\n"); + } + if(!forwardDeclaredClassNames.isEmpty()) + sb.append("\n"); + generateClass(sb, cls); + sb.append("} // namespace DawProject\n"); + final var classHeaderFile = new File(targetPathString + cls.getSimpleName() + ".h"); + Files.write(classHeaderFile.toPath(), Collections.singleton(sb.toString()), StandardCharsets.UTF_8); + Assert.assertTrue(classHeaderFile.exists()); + } + } + + private boolean isRelevantSuperClass(Class superclass) + { + return superclass != Object.class && superclass != Referenceable.class; + } + + private void generateEnums(StringBuilder sb) + { + boolean isFirst = true; + for(final var values : enums) + { + if(isFirst) + isFirst = false; + else + sb.append("\n"); + generateEnum(sb, values); + } + } + + private void generateEnumEntryName(StringBuilder sb, String enumName, String entryName) + { + for (int i = 0; i < enumName.length(); i++) + { + final var c = enumName.charAt(i); + if(Character.isUpperCase(c) && i != 0) + { + sb.append("_"); + } + sb.append(Character.toString(c).toUpperCase()); + } + + sb.append("_"); + sb.append(entryName.toUpperCase()); + } + + private void generateEnum(final StringBuilder sb, final Enum[] values) + { + final var name = values[0].getClass().getSimpleName(); + sb.append("enum " + name + ": int\n{\n"); + for (Enum value : values) + { + sb.append(" "); + generateEnumEntryName(sb, name, value.name()); + sb.append(" = "); + sb.append(value.ordinal()); + sb.append(",\n"); + } + + sb.append("};\n"); + } + + private void appendJavaDoc(final StringBuilder sb, final BaseJavadoc javadoc, int indentation) + { + if (javadoc.isEmpty()) + return; + final var comment = formatter.format(javadoc.getComment()); + if (comment.isEmpty()) + return; + final var indent = " ".repeat(indentation); + sb.append(indent + "/* "); + sb.append(comment.replace("\n", "\n" + indent)); + sb.append(" */\n"); + } + + private void generateClass(final StringBuilder sb, final Class cls) + { + appendJavaDoc(sb, RuntimeJavadoc.getJavadoc(cls), 0); + + final var name = cls.getSimpleName(); + sb.append("struct " + name + "\n"); + + var superClass = cls.getSuperclass(); + if (isRelevantSuperClass(superClass)) + sb.append(" : public " + superClass.getSimpleName() + "\n"); + + sb.append("{\n"); + + for (final var field : cls.getDeclaredFields()) + { + if(Modifier.isStatic(field.getModifiers())) + continue; + final var fieldJavadoc = RuntimeJavadoc.getJavadoc(field); + generateStructField(sb, field, fieldJavadoc); + } + + sb.append("};\n"); + } + + private void generateStructField(final StringBuilder sb, final Field field, final FieldJavadoc fieldJavadoc) + { + final String commentText = fieldJavadoc != null && !fieldJavadoc.isEmpty() ? fieldJavadoc.getComment().toString() : ""; + + final var isCommentLong = commentText.length() > 50 || commentText.contains("\n"); + + if (isCommentLong) + appendJavaDoc(sb, fieldJavadoc, 4); + + var typeString = getTypeString(field); + if(isIdRef(field)) + typeString = typeString + "*"; + else if(!isRequired(field) && !isListOrArray(field)) + typeString = "std::optional<" + typeString + ">"; + sb.append(" "); + sb.append(typeString + " " + getFieldName(field)); + sb.append(";"); + + if (!isCommentLong && !commentText.isEmpty()) + { + sb.append(" // "); + sb.append(commentText); + } + sb.append("\n"); + } + + private boolean isListOrArray(final Field field) + { + final var type = field.getType(); + return type.isArray() || type == List.class; + } + + private boolean isIdRef(final Field field) + { + return field.getAnnotation(XmlIDREF.class) != null; + } + + private boolean isRequired(final Field field) + { + for (final var annotation : field.getAnnotations()) + { + if (annotation instanceof XmlElementWrapper e && e.required()) + return true; + else if (annotation instanceof XmlElement e && e.required()) + return true; + else if (annotation instanceof XmlElementRef e && e.required()) + return true; + else if (annotation instanceof XmlAttribute e && e.required()) + return true; + } + return false; + } + + private String getTypeString(final Class type) + { + if (type == String.class) + return "std::string"; + if (type == Integer.class) + return "int"; + if (type == Double.class) + return "double"; + if (type == Boolean.class) + return "bool"; + if (type == double.class) + return "double"; + if (type == int.class) + return "int"; + if (type.isArray()) + return "std::vector<" + getTypeString(type.getComponentType()) + ">"; // recursive call for getTypeString! + return type.getSimpleName(); + } + + private String getTypeString(final Field field) + { + final Class type1 = field.getType(); + if (type1 == List.class) + return "std::vector<" + getListGenericType(field).getSimpleName() + ">"; + + return getTypeString(field.getType()); + } + + private static String getFieldName(final Field field) + { + return field.getName(); + } + + Class getListGenericType(final Field field) + { + if (field.getGenericType() instanceof ParameterizedType pt && pt.getActualTypeArguments().length == 1) + { + final var listType = pt.getActualTypeArguments()[0]; + if (listType instanceof Class cls) + return cls; + } + return null; + } + + private static final CommentFormatter formatter = new CommentFormatter(); +}