Daw Project Export Tool for Renoise 3.5+ (early state)

A very early state, kind of a scaffolding of a daw project export tool (and later import maybe) for the Renoise DAW, starting from version 3.5 and upwards.

Sadly it is not possible currently to provide a complete tool without a lot of workarounds, due to API limitations. These would be easy to add, because everything already is implemented under the hood, just not made available in the API. Please read my suggestions for the Renoise API below.

Working so far

  • Auto converts Renoise sample instruments into Redux instances, to make it loadable in the target DAW
  • Note data and song structure
  • Plugin automation data
  • Section naming
  • Track coloring and naming
  • Loads fine into Bitwig 5.3+ (all) and Studio One 7.2+ (VST3 completely, AU without automation)
  • You can also convert any sample instrument to Redux VST3 via context menu
  • AudioUnit preset and automation export (not working in S1, due to bugs in S1)
  • VST2 preset and automation export (not working in S1, due to bugs in S1)
  • VST3 preset and automation export (some rosetta2 / x64 plugins won’t work)

Partly working so far

  • Workaround VST2 preset export (via included VST2 helper tool)
  • Workaround VST2 automation (via included VST2 helper tool)
  • Workaround VST3 automation (via included VST3 helper tool)

What’s not working / not implemented yet

  • Master track automation conversion
  • Any kind of pattern hex automation conversion
  • Redux macro device to instrument device automation conversion
  • polyphonic aftertouch
  • No idea why VST3 preset loading fails in Cubase 14+. Might be the preset data itself. As a workaround, load the exported dawproject into S1 and then again export as dawproject. Bitwig exports also fail to load in Cubase. S1 uses an uncompressed zip type.
  • VST2 preset loading and mapping is buggy in Studio One currently and needs to be fixed.
  • Studio One will incorrectly set/interpret the parameter ids for AudioUnits. Therefore automation for AudioUnits currently is lost in Studio One.

This can’t work using API only, due to the API limitations

  • VST2/AU preset generation/export. Renoise does not provide any way to get the .fxp / .aupreset data. The device.active_preset data only contains the individual inline song data of the VST2 or AU plugin, assumingly different to VST3. This is already implemented in Renoise via “import preset…” and “export preset…”, just not made available in the API for unknown reasons.
  • VST3 preset export might be wonky, because it grabs the preset data from device.active_preset_data’s <ParameterChunk> node, assuming that this is simply the complete .vstpreset. But it might not be the case for every plugin…
  • parameterID mapping, so most automation won’t work, except for some VST3 plugins still using the index as parameter id (e.g. Redux VST3)
  • The correct VST2 plugin identifier can’t be set (an integer, which you see as “Unique ID” in the plugin info tooltip), since it is neither available in the API nor in device.active_preset_data, but required for VST2 preset loading
  • You can’t determine the target device of the “Instr. Automation Device” via API currently. Has to be done through a complete track search instead (so the device has to sit on the track where the instrument plays). That <LinkedInstrument> node is missing in the active_preset_data for some reason, if you access it via API (not copy-paste).
  • An import can only work for the song structure, but not for preset transferring, due to the same API limitations.
  • AudioUnit parameter mapping is not possible, due to missing parameter ID infos.

Song requirements

A song has to fulfill the following requirements for a working export:

  • Only one instrument per track! Use Fladd’s track splitter tool!
  • The Instr. Automation Device has to be placed onto the track where the target instrument is playing.

Automatic workarounds

The tool can use VST2/3 info tools to extract the missing plugin infos, which I coded in Rust. There are pre-built binaries included in the /bin sub directory, pre-built for macOS (arm/intel ub2), windows x86_64, linux x86_64.

Manual workarounds

  • You can manipulate the generated dawproject data inside the “tmp” directory of the tool and then use the “Repack .dawproject” menu entry.

How to build from source

macOS and Linux users use the ./build_for_mac_linux.sh script. Might need a chmod +x first. Windows users can test the same script, which should work in Windows 11 at least.

You can also decide to build a bunch of binary vst-tools that I’ve lamely coded in Rust.

These tools try to circumvent the current limitations of the Renoise API. The VST2/VST3 tool will give detailed infos for a given plugin path. If you want to use those via the tool settings, you will have to build these as first step with ./build_vst_tools.sh.

The tools require Rust / cargo to be installed on the system.

Feel free to contribute

Feel free to improve, try yourself, get in touch, and discuss it. Contact me, if you have questions or ideas.

I have tested this tool so far for macOS. However, it should theoretically also work for Windows and maybe even Linux. Please report back.

I’ve also tried to make the source code nicely readable. You know, this is important for team work, like proper function-, variable- and parameter-naming. The goal should be that a new developer can understand what’s going on on-the-fly. What is the method or object actually doing?

Suggestions for the API

renoise.DeviceParameter.plugin_parameter_id - int, unique VST3 parameter id provided by the plugin, is a simple index for VST2 (should be avaialable for AudioUnit, too)

renoise.AudioDevice:export_active_preset(file_path) - saves the currently selected preset in plugin specific format, that is .vstpreset for VST3, .fxp for VST2, .aupreset for AudioUnit. Just as “export preset…”

renoise.InstrumentPluginDevice:export_active_preset(file_path) - saves the currently selected preset in plugin specific format, that is .vstpreset for VST3, .fxp for VST2, .aupreset for AudioUnit. Just as “export preset…”

renoise.AudioDevice:import_active_preset(file_path) - imports a plugin type format specific preset into the active preset. Just as “import preset…”

renoise.InstrumentPluginDevice:import_active_preset(file_path) - imports a plugin type format specific preset into the active preset. Just as “import preset…”

renoise.AudioDevice.unique_id - Just as “Unique ID” in the info tooltip. Renoise does not use it for VST2, instead it uses the plugin filename. But the actual ID is needed for the export.

renoise.InstrumentPluginDevice.unique_id - Just as “Unique ID” in the info tooltip. Renoise does not use it for VST2, instead it uses the plugin filename. But the actual ID is needed for the export.

renoise.AudioDevice.active_preset_data["LinkedInstrument"] - Also contains LinkedInstrument node for Instr. Automation Device

Uses the following libraries

JSON lua by RXI

xml2lua by Manoel Campos da Silva Filho, Paul Chakravarti

Also FancyStatus and ProcessSlicer.

License

Licensed under CC Attribution-NonCommercial-ShareAlike 4.0 International - Deed - Attribution-NonCommercial-ShareAlike 4.0 International - Creative Commons

Can be changed.

Disclaimer

This Renoise tool currently contains pre-built binaries of the VST info helper tools. I built those on my macOS system using the recommended toolchains for Rust. If you are unsure you can build these yourself, or simply disable the usage in the tool’s preferences. Building will require basic knowledge about how to setup a Rust dev environment. macOS should work best for that purpose.

So I am not responsible for any damage these binaries could do to your system and your data. Use at your own risk!

However, the binaries appear to behave normally here :wink:

Download

Automatic release builds

Source code

9 Likes

For pattern commands you may be able to rip out some things from my following tool here, which can convert some pattern commands to envelopes, at least for those supporting it. Been 14 years though, so don’t ask me into too much detail what’s going on. :stuck_out_tongue:

https://www.renoise.com/tools/copy-automation

If i’m not mistaken VST2 presets may be embedded in the song.xml as base64 encode.

1 Like

Hi, thanks for your suggestions! However, the Song.xml contains the exact same data as the data the tool is already grabbing from the device.active_preset_data. And this is a different data than actually required and provided via “export preset”. I have no idea if you also could make a valid .fxp preset file from that inline chunkdata, but it looks different content wise.

TB_Spectogram_V1 VST2 - preset data via “export preset” context menu (required for dawproject):

TB_Spectogram_V1 VST2 - inline song data via device.active_preset_data[Chunkdata] and via Song.xml (it’s the same):

I think there is no way to create a proper VST2 preset via the lua API currently. I assume the VST2, VST3 and AU plugin APIs provide functionality like “give inline data” and “give preset data”… Very unclear for me here. The solution is what I mentioned as suggestions for the API above. Plus no plugin identifier for VST2, and no magic string (“T1SG”) for the fxp either available.

Have you researched the fxp format? It seems fairly straightforward to chuck a binary header onto the Base64 data and get a valid fxp file. One possible reference: GitHub - CharlesHolbrow/vst2-preset-parser: vst2 .fxp and .fxb binary file parser for node.js

Sure, I already thought about that, but Renoise API lacks of required info to create that header properly. Can’t create these guys:

Also there seems to be a difference in content for the actual content, see above. However, thanks for the feedback and link!

1 Like

FYI: I’ve added now a github workflow, so with each merge into main, it should auto-build a release. Hopefully, you can now download the recent build directly from github (link in post #1).

I hope it will always add the last commit message of the merged branch to the release info text… But unsure here. Might be something like “merged Vx.y into main” instead :sweat_smile:

1 Like
Criminal info
//-------------------------------------------------------------------------------------------------------
// VST Plug-Ins SDK
// Version 2.4		$Date: 2006/02/09 11:05:51 $
//
// Category     : VST 2.x Interfaces
// Filename     : vstfxstore.h
// Created by   : Steinberg Media Technologies
// Description  : Definition of Program (fxp) and Bank (fxb) structures
//
// ďż˝ 2006, Steinberg Media Technologies, All Rights Reserved
//-------------------------------------------------------------------------------------------------------

#ifndef __vstfxstore__
#define __vstfxstore__

#ifndef __aeffect__
#include "aeffect.h"
#endif

//-------------------------------------------------------------------------------------------------------
/** Root chunk identifier for Programs (fxp) and Banks (fxb). */
#define cMagic				'CcnK'

/** Regular Program (fxp) identifier. */
#define fMagic				'FxCk'

/** Regular Bank (fxb) identifier. */
#define bankMagic			'FxBk'

/** Program (fxp) identifier for opaque chunk data. */
#define chunkPresetMagic	'FPCh'

/** Bank (fxb) identifier for opaque chunk data. */
#define chunkBankMagic		'FBCh'

/* 
	Note: The C data structures below are for illustration only. You can not read/write them directly.
	The byte order on disk of fxp and fxb files is Big Endian. You have to swap integer
	and floating-point values on Little Endian platforms (Windows, MacIntel)!
*/

//-------------------------------------------------------------------------------------------------------
/** Program (fxp) structure. */
//-------------------------------------------------------------------------------------------------------
struct fxProgram
{
//-------------------------------------------------------------------------------------------------------
	VstInt32 chunkMagic;		///< 'CcnK'
	VstInt32 byteSize;			///< size of this chunk, excl. magic + byteSize

	VstInt32 fxMagic;			///< 'FxCk' (regular) or 'FPCh' (opaque chunk)
	VstInt32 version;			///< format version (currently 1)
	VstInt32 fxID;				///< fx unique ID
	VstInt32 fxVersion;			///< fx version

	VstInt32 numParams;			///< number of parameters
	char prgName[28];			///< program name (null-terminated ASCII string)

	union
	{
		float params[1];		///< variable sized array with parameter values
		struct 
		{
			VstInt32 size;		///< size of program data
			char chunk[1];		///< variable sized array with opaque program data
		} data;					///< program chunk data
	} content;					///< program content depending on fxMagic
//-------------------------------------------------------------------------------------------------------
};

//-------------------------------------------------------------------------------------------------------
/** Bank (fxb) structure. */
//-------------------------------------------------------------------------------------------------------
struct fxBank
{
//-------------------------------------------------------------------------------------------------------
	VstInt32 chunkMagic;		///< 'CcnK'
	VstInt32 byteSize;			///< size of this chunk, excl. magic + byteSize

	VstInt32 fxMagic;			///< 'FxBk' (regular) or 'FBCh' (opaque chunk)
	VstInt32 version;			///< format version (1 or 2)
	VstInt32 fxID;				///< fx unique ID
	VstInt32 fxVersion;			///< fx version

	VstInt32 numPrograms;		///< number of programs

#if VST_2_4_EXTENSIONS
	VstInt32 currentProgram;	///< version 2: current program number
	char future[124];			///< reserved, should be zero
#else
	char future[128];			///< reserved, should be zero
#endif

	union
	{
		fxProgram programs[1];	///< variable number of programs
		struct
		{
			VstInt32 size;		///< size of bank data
			char chunk[1];		///< variable sized array with opaque bank data
		} data;					///< bank chunk data
	} content;					///< bank content depending on fxMagic
//-------------------------------------------------------------------------------------------------------
};

#endif // __vstfxstore__

Additional info
/**
 * A Vst2 Patch or Bank.
 * `.fxp` files will have a `.state64` string
 * `.fxp` files will have one of: `.patchParams` or `.patchChunk`
 * `.fxb` files will have one of: `.bankPatches` or `.bankChunk`
 * @typedef {Object} Vst2Preset
 * @property {string} fxMagic - one of: 'FxCk', 'FPCh', 'FxBk', 'FBCh'
 * @property {number} version - format version (typically 1)
 * @property {number} idUint - unique plugin id Number
 * @property {number} idString - unique plugin id as a string
 * @property {number} fxVersion -
 * @property {number} count - number of parameters (for FxCk patches). Number of programs (for FxBk banks)
 * @property {number[]} [patchParams] - all parameter values (for FxCk .fxp files)
 * @property {Buffer} [patchChunk] - binary state (for FPCh .fxp files)
 * @property {Vst2Preset[]} [bankPatches] - all patches in the bank (for FxBk .fxb files)
 * @property {Buffer} [bankChunk] - binary state (for FBCh .fxb files)
 * @property {string} [state64] - base64 encoded state (for all .fxp files)
 */

Published v0.1.2 now, containing the following additions:

  • vst2 preset generation (.fxp) - read below
  • Added a vst2 info tool, which I coded in Rust, to extract the missing data from a plugin, e.g. unique identifier. Binaries for macOS, Windows and also Linux are included in the /bin dir inside the tool
  • Pitchbend, midi cc automation. Also fixed the plugin<->automation mapping

There still is something wrong with the vst2 preset generation. Even though you can manually load the generated .fxp files successfully into the fitting vst2 in a lot of cases (e.g. A1StereoControl), it does not seem to load automatically in S1 and Bitwig. The plugins are correctly loaded though.

Some vst2 fxp preset generation does not seem to work, this might be caused be the provided chunkdata in active_preset_data. For example fxps of tone boosters plugins look valid in the hex editor but simply load as init into the plugins. The chunkdata also is way bigger than the data which Renoise generates while an fxp export.

Maybe @taktik could give me a hint here what’s going on, why the chunkdata is so much bigger than exported data, after his break of course.

Next up I am trying to build a VST3 info tool :joy: Or taktik will be faster… Well, Rust actually is quite impressive. I can really easily build cross platform, it’s so modern, omg. The only not modern: For some reason it’s using snake case :face_exhaling: So I am learning Rust while building this tool.

Songs seem to load fine into Bitwig and S1, mostly with automation. Sometimes Bitwig shows an “unknown” automation lane. This is due to a VST3 plugin using parameter IDs instead the index, all the TB plugins for example. At least you can copy then the automation.

Generated fxp on the left, exported fxp on the right. Can’t find a difference (except 0x10 bytes longer). Must be another reason then. Maybe filenaming? Ah maybe the preset name! EDIT: fxp loading in Bitwig seems to be fixed for A1StereoTool, but not in S1…

1 Like

I was bored so I tried to spot the difference: programName and OutputGain have different values.

1 Like

Thanks :slight_smile: But that’s inside the chunk data, so it’s ok.

I’ve uploaded a new fix, so for now, bridged vst2 plugins won’t be exported, since my vst2info tool can’t check a vst cross-cpu-archtecture. I guess I will have to split the mac tool into x64 and arm, and then load each plugin as its architecture.

I`ve fixed it, so it now can use the info tool for bridged plugins (two separate builds). And added more coroutine.yield calls. It still can cause a warning modal due to long execution time, e.g. reading and converting huge parameter chunks of slow, bridged plugins seems to be a bottle neck. Just keep clicking on continue execution :wink:

I can export now quite complex songs and all tracks play in bitwig., including all vstpresets and most fxps. For some still unknown reason, the fxps do not load in studio one. It loads it’s own exported ones correctly. Can’t spot a difference… It’s all spec conform now as I can tell. Bitwig has a bug, if you directly export an imported dawproject, it will mess up the instruments. So this can’t be used as a workaround… I reported this bug months ago… Maybe it can be fixed if you move the instruments around, no idea.

2 Likes

v0.1.5 - Added now a VST3 info tool. So far it only can readout VST3 fx, but not most VST3 instruments… But parameter id mapping for fx now works via the tool.

Can compile the tool for macos only… First check the tool setting, you might have to disable the vst3 info tool usage first. Should work on macos… Annoying, these workarounds…

This is the rust vst3 info tool: DawProject-Tool/vst3info-tool/src/main.rs at main · Jurek-Raben/DawProject-Tool · GitHub

It can load some instruments only, often gives a “seg fault”… I’ve ripped the code mostly from here: GitHub - HelgeSverre/rust-vst3-host

This tool has the same loading problems sadly…

Ok, I’ve found out that Studio One currently has multiple bugs when it comes to dawproject import/export and VST2:

  • While an import, preset is not loaded, even if it is a valid fxp format (even loads it correctly if done manually)
  • While an export, parameterIDs are incorrectly mapped for VST2s. Some “magic” id is used instead of the index (VST2 spec has no way to set a ID for a parameter)

I’ve tried to report these issues, but the support is quite annoying/not helpful and does not seem to understand normal words, or something. Let’s see…

I’ve added AU preset and automation export. S1 currently seems to be buggy regarding AUs in dawproject files though. Hope they will come up with a fix. It was quite easy this time, since I simply could use the preinstalled command line tools auval and plutil.

I’ve fixed the vst3info tool now at least for macos, so it works with multi module vst3s like Zebra2HZ.vst3. No idea, if this Rust tool works for Windows and Linux.

EDIT: The vst3info tool does not seem to work properly in Rosetta2/x64 mode, only for a few plugins. These complex workarounds are quite annoying… Next up recoding Renoise or something…