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!!
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!!
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
Is there any documentation on the encoding of serum presets?
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.
@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…
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.
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'])
@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.