File Types???

Started by Alexander Porras
Avatar for Alexander Porras

Alexander Porras

Could someone please tell me the difference between an .FXP file and a .NMSV file? i think this is the reason my recently purchased presets arent working. 
Please help!!

Avatar for steve_xfer

steve_xfer

NMSV = Native Instruments Massive

FXP = "VST" preset.  You can't be sure what synth it is for without opening  it in a hex viewer (or maybe a text editor).  
For instance, Serum presets will show "XfsX" for the 16-20th chars of the file.

-Steve
 

Avatar for atmik

atmik

Is there any documentation on the encoding of serum presets?

Avatar for steve_xfer

steve_xfer

Serum preset file format is complex/programmatic and isn't public. I hope to make it more open in the future / new format with conversion or import.

There is public info on the Serum wavetable format.
This is an example 'clm ' chunk from a Serum-created wavetable (.wav) File:

<!>2048 01000000 wavetable (www.xferrecords.com)
Serum currently assumes 2048 (samples per frame) at all times, so as of now 2048 should always be written there.

Only the two first flags are currently used:

• the first flag is the WT interpolation [0 = no interpolation, 1 = linear crossfades, 2,3,4 = spectral morph]

• the second flag is "Serum Factory WT" which means Serum assumes this file comes with Serum and everyone already has it - thus it will not embed in to user presets to keep file sizes down. PLEASE DO NOT ENABLE THIS FLAG IF YOU ARE CREATING WAVETABLES - please leave it to zero, thank you very much. If you want a similar flag for yourself to identify tables as factory or otherwise for your product, drop me a line and I will reserve you a flag or a different value on that flag.

Avatar for Darcey

Darcey

@steve_xfer
Any news on making the move to json / plain text (/r/n) presets for serum? (eg. u-he, spire etc).

I would love to clean up the noises and tables folders and then make a tool go through each preset and automatically update the paths to the noise and/or table. It would take a silly amount of time to do this in serum…

Avatar for steve_xfer

steve_xfer

I looked in to it and am keeping things in binary to keep presets small and loading fast (which is blazing fast in the next update). Table locations don't matter, and Noises will recursively search in the next beta.

Avatar for devalias

devalias

Originally posted this on another forum (ref), but wanted to share it here also for completeness, since this is one of the top places that comes up when googling for the serum patch file format.

This has always been an idea floating around in the back of my mind and pondering the easiest way to do it. Over the last couple of days I was playing around with Spotify's pedalboard, and using it to load VST plugins (eg. Serum) from python code:

I found that once the plugin is loaded, we can access the 'parameters', which seems to be a collection of all(?) of the synth params, and their values, etc.

I then figured out that we can show the plugin GUI, manually load a patch, and then close the GUI and read the updated values; which seems to allow us to extract the data that was contained in that patch; even without knowing the exact binary format of the file itself. I tried this using the Serum demo, and it seemed to work.

You could then potentially also use this method of data extraction to help in reversing the binary file format of a Serum patch if that was still desired; though for many use cases, this sort of bypasses the need to.

Basic PoC python code for this:

from pedalboard import Pedalboard, load_plugin

synth_plugin = load_plugin("/Library/Audio/Plug-Ins/Components/Serum.component")

print("Capturing initial state of synth params..")
initial_synth_params = {key: synth_plugin.parameters[key].raw_value for key in synth_plugin.parameters.keys()}

print("Showing synth GUI..")
synth_plugin.show_editor()

print("Capturing state of synth params after showing GUI..")
new_synth_params = {key: synth_plugin.parameters[key].raw_value for key in synth_plugin.parameters.keys()}

# Calculate the differences
synth_param_diffs = {
  key: {'before': initial_synth_params[key], 'after': new_synth_params[key]}
  for key in initial_synth_params
  if initial_synth_params[key] != new_synth_params[key]
}

# Print out the differences
print(f"Number of parameters before: {len(initial_synth_params)}")
print(f"Number of parameters after: {len(new_synth_params)}")
print(f"Number of parameters changed: {len(synth_param_diffs)}")
for key, value in synth_param_diffs.items():
    print(f"Parameter: {key} ({synth_plugin.parameters[key].name}), Before: {value['before']}, After: {value['after']}")

Here are all of the parameter key names visible from the Serum demo AU plugin:

from pedalboard import load_plugin, 

synth_plugin = load_plugin("/Library/Audio/Plug-Ins/Components/Serum.component")

# Print out the parameter keys supported by the synth plugin
print(synth_plugin.parameters.keys())
dict_keys(['mastervol', 'a_vol', 'a_pan', 'a_octave', 'a_semi', 'a_fine', 'a_unison', 'a_unidet', 'a_uniblend', 'a_warp', 'a_coarsepit', 'a_wtpos', 'a_randphase', 'a_phase', 'b_vol', 'b_pan', 'b_octave', 'b_semi', 'b_fine', 'b_unison', 'b_unidet', 'b_uniblend', 'b_warp', 'b_coarsepit', 'b_wtpos', 'b_randphase', 'b_phase', 'noise_level', 'noise_pitch', 'noise_fine', 'noise_pan', 'noise_randphase', 'noise_phase', 'sub_osc_level', 'sub_osc_pan', 'env1_atk', 'env1_hold', 'env1_dec', 'env1_sus', 'env1_rel', 'osca_fil', 'oscb_fil', 'oscn_fil', 'oscs_fil', 'fil_type', 'fil_cutoff', 'fil_reso', 'fil_driv', 'fil_var', 'fil_mix', 'fil_stereo', 'env2_atk', 'env2_hld', 'env2_dec', 'env2_sus', 'env2_rel', 'env3_atk', 'env3_hld', 'env3_dec', 'env3_sus', 'env3_rel', 'lfo1rate', 'lfo2rate', 'lfo3rate', 'lfo4rate', 'porttime', 'portcurve', 'chaos1_bpm', 'chaos2_bpm', 'chaos1_rate', 'chaos2_rate', 'a_curve1', 'd_curve1', 'r_curve1', 'a_curve2', 'd_curve2', 'r_curve2', 'a_curve3', 'd_curve3', 'r_curve3', 'verb_wet', 'verbsize', 'verbpdly', 'verbloct', 'verbdamp', 'verbhict', 'verbwdth', 'eq_frql', 'eq_frqh', 'eq_q_l', 'eq_q_h', 'eq_voll', 'eq_volh', 'eq_typl', 'eq_typh', 'dist_wet', 'dist_drv', 'dist_l_b_h', 'dist_mode', 'dist_freq', 'dist_bw', 'dist_prepost', 'flg_wet', 'flg_bpm_sync', 'flg_rate', 'flg_dep', 'flg_feed', 'flg_stereo', 'phs_wet', 'phs_bpm_sync', 'phs_rate', 'phs_dpth', 'phs_frq', 'phs_feed', 'phs_stereo', 'cho_wet', 'cho_bpm_sync', 'cho_rate', 'cho_dly', 'cho_dly2', 'cho_dep', 'cho_feed', 'cho_filt', 'dly_wet', 'dly_freq', 'dly_bw', 'dly_bpm_sync', 'dly_link', 'dly_timl', 'dly_timr', 'dly_mode', 'dly_feed', 'dly_off_l', 'dly_off_r', 'cmp_thr', 'cmp_rat', 'cmp_att', 'cmp_rel', 'cmpgain', 'cmpmbnd', 'fx_fil_wet', 'fx_fil_type', 'fx_fil_freq', 'fx_fil_reso', 'fx_fil_drive', 'fx_fil_var', 'hyp_wet', 'hyp_rate', 'hyp_detune', 'hyp_unison', 'hyp_retrig', 'hypdim_size', 'hypdim_mix', 'dist_enable', 'flg_enable', 'phs_enable', 'cho_enable', 'dly_enable', 'comp_enable', 'rev_enable', 'eq_enable', 'fx_fil_enable', 'hyp_enable', 'oscapitchtrack', 'oscbpitchtrack', 'bend_u', 'bend_d', 'warposca', 'warposcb', 'suboscshape', 'suboscoctave', 'a_uni_lr', 'b_uni_lr', 'a_uni_warp', 'b_uni_warp', 'a_uni_wtpos', 'b_uni_wtpos', 'a_uni_stack', 'b_uni_stack', 'mod_1_amt', 'mod_1_out', 'mod_2_amt', 'mod_2_out', 'mod_3_amt', 'mod_3_out', 'mod_4_amt', 'mod_4_out', 'mod_5_amt', 'mod_5_out', 'mod_6_amt', 'mod_6_out', 'mod_7_amt', 'mod_8_out', 'mod_8_amt', 'mod_9_amt', 'mod_9_out', 'mod10_amt', 'mod10_out', 'mod11_amt', 'mod11_out', 'mod12_amt', 'mod12_out', 'mod13_amt', 'mod13_out', 'mod14_amt', 'mod14_out', 'mod15_amt', 'mod15_out', 'mod16_amt', 'mod16_out', 'osc_a_on', 'osc_b_on', 'osc_n_on', 'osc_s_on', 'filter_on', 'mod_wheel', 'macro_1', 'macro_2', 'macro_3', 'macro_4', 'amp', 'lfo1_smooth', 'lfo2_smooth', 'lfo3_smooth', 'lfo4_smooth', 'pitch_bend', 'mod17_amt', 'mod17_out', 'mod18_amt', 'mod18_out', 'mod19_amt', 'mod19_out', 'mod20_amt', 'mod20_out', 'mod21_amt', 'mod21_out', 'mod22_amt', 'mod22_out', 'mod23_amt', 'mod23_out', 'mod24_amt', 'mod24_out', 'mod25_amt', 'mod25_out', 'mod26_amt', 'mod26_out', 'mod27_amt', 'mod27_out', 'mod28_amt', 'mod28_out', 'mod29_amt', 'mod29_out', 'mod30_amt', 'mod30_out', 'mod31_amt', 'mod31_out', 'mod32_amt', 'mod32_out', 'lfo5rate', 'lfo6rate', 'lfo7rate', 'lfo8rate', 'lfo5_smooth', 'lfo6_smooth', 'lfo7_smooth', 'lfo8_smooth', 'fxfil_pan', 'comp_wet', 'gain_l', 'gain_m', 'gain_h', 'lfo1_rise', 'lfo2_rise', 'lfo3_rise', 'lfo4_rise', 'lfo5_rise', 'lfo6_rise', 'lfo7_rise', 'lfo8_rise', 'lfo1_delay', 'lfo2_delay', 'lfo3_delay', 'lfo4_delay', 'lfo5_delay', 'lfo6_delay', 'lfo7_delay', 'lfo8_delay'])
Avatar for udisoft

udisoft

@steve_xfer
Let us assume a developer wants to generate save presets as '.fxp' files which can again be loaded to Serum without any issue. I understand that the preset file format is not public. Is there an alternative option provided by Xfer like a compiled library or an API to achieve that? Thanks.

Avatar for devalias

devalias

I noticed that in Serum 2 there seems to be a new preset file format (*.SerumPreset), that from a quick peek in a hex editor (ref) seems to be using a new XferJson format (at least for the header), and seems to contain a bunch of easily parseable JSON before what appears to be a zlib compressed stream of presumably the rest of the preset data.

Serum preset file format is complex/programmatic and isn't public. I hope to make it more open in the future / new format with conversion or import.

I was wondering, with this new format, is there any public documentation for it? Or plans to publish such?

And has your view on whether to make the old Serum 1.x preset format public changed over the years?

Avatar for devalias

devalias

From a podcast with @steve_xfer, at 53:08'ish he talks about wanting to open-source the preset format at some point:

  • https://youtu.be/QmbM-eP-zQw?list=PLDxTQYPyq4JQzYc29ltUgBh8LkMVnNFbl&t=3188
    • I do think about opening up the serum preset format which is something that I'd like to do at some point in the future um so that if someone wanted to make a utility to try to convert some synth presets into serum or vice versa that they would have more um more access to being able to attempt that or like AI generate presets and stuff like that which I personally am a little opposed to but I I don't really want to stop people from trying so right now serum presets when I say serum preset I mean serum 2 preset they're a Json format but it's like Json compressed so it's not human readable um and we do that not only to save disk space but also it actually loads a lot faster so it's more performant um but in theory we could have an option that you could save as with it uncompressed and then at that point you're left with like you have with Ableton Live you have this sort of human readable file describing everything that's been moved off of its default value um and that can be kind of interesting um it would take a lot of work for someone but in theory someone could make you know Python scripts or whatever it is that could generate presets from script or whatever it is they'd want to imagine uh but we have to sort of provide them with that and documentation first so um it's not a priority probably serum 2.1 or 2.5 though I'd like I would like to open that up to people