Skip to content

Instantly share code, notes, and snippets.

@ryrun
Last active May 1, 2021 15:34
Show Gist options
  • Save ryrun/0fdea630065d3164310931819c6ee1d7 to your computer and use it in GitHub Desktop.
Save ryrun/0fdea630065d3164310931819c6ee1d7 to your computer and use it in GitHub Desktop.
It generates Bitwig presets (.bwpreset), Renoise .xrni patches and Komplete Kontrol .nksf Patches of vst instrument patches (.fxp) with automatically generated meta data. Its written for windows and uses 7z to compress the fxp patch for bitwig and renoise patches. Other implementation as PHP scripts: https://github.com/ryrun/PHPBitwigPresetGen
;;; https://github.com/jhorology/gulp-bitwig-rewrite-meta/blob/master/gulp-bitwig-rewrite-meta.coffee
(require 'bindat)
;;; gen for komplete kontrol
(defun create-nksf (fxp id devicefilename devicecreator presetname category tags bank comment)
(setq vstname (substring devicefilename 0 -4))
;;load fxp
(let ((coding-system-for-read 'binary))
(setq fxp (substring
(with-temp-buffer
(set-buffer-multibyte nil)
(setq buffer-file-coding-system 'binary)
(insert-file-contents fxp)
(buffer-string))
60)))
;;chunk aligment
(setq fxplen (length fxp))
(if (= (mod (length fxp) 2) 1)
(setq fxp (concat
fxp
(char-to-string #x0)
)))
;;uuid
;;(setq uuid "a081f4ba-9608-438f-8a87-def6a42e3d81")
(if (> (length bank) 0)
(setq bankchain (concat
(char-to-string #x92) ;; array 2 item
(char-to-string #xd9) (char-to-string (min 255 (length vstname))) vstname
(char-to-string #xd9) (char-to-string (min 255 (length bank))) bank))
(setq bankchain (concat
(char-to-string #x91) ;; array 1 item
(char-to-string #xd9) (char-to-string (min 255 (length vstname))) vstname))
)
;;build patch
(setq ret (concat
;;(char-to-string #x87)
(char-to-string #xd9) (char-to-string 6) "author"
(char-to-string #xa0)
(char-to-string #xd9) (char-to-string 9) "bankchain"
bankchain
(char-to-string #xd9) (char-to-string 7) "comment"
(char-to-string #xd9) (char-to-string (min 255 (length comment))) comment
(char-to-string #xd9) (char-to-string 4) "name"
(char-to-string #xd9) (char-to-string (min 255 (length presetname))) presetname
(char-to-string #xd9) (char-to-string 10) "deviceType"
(char-to-string #xd9) (char-to-string 4) "INST"
(char-to-string #xd9) (char-to-string 6) "vendor"
(char-to-string #xd9) (char-to-string (min 255 (length devicecreator))) devicecreator
;;(char-to-string #xd9) (char-to-string 4) "uuid"
;;(char-to-string #xd9) (char-to-string (min 255 (length uuid))) uuid
(char-to-string #xd9) (char-to-string 5) "types"
(char-to-string #x91) ;; array 1 item
(char-to-string #x91) ;; array 1 item
(char-to-string #xd9) (char-to-string (min 255 (length category))) category
))
;;add tags, when set
(if (> (length tags) 0)
(progn
(setq tagcount (length (split-string tags " ")))
;;increase count of maps and prepare tag array
(setq ret (concat
(char-to-string #x88)
ret
(char-to-string #xd9) (char-to-string 5) "modes"
(char-to-string #xdc) ;; array
(bindat-pack '((data u16)) `((data . ,tagcount)))
))
;;add each tag
(seq-do
(lambda (el)
(setq ret (concat
ret
(char-to-string #xd9) (char-to-string (min 255 (length el))) el
))
)
(split-string tags " "))
)
;;no tags
(setq ret (concat
(char-to-string #x87)
ret))
)
;;chunk aligment
(if (= (mod (length ret) 2) 1)
(setq ret (concat
ret
(char-to-string #x0)
)))
;;final lnegth of chunk
(setq nisilen (length ret))
(setq ret (concat
ret
;;;vst magic riff
"PLID"
[#x14 0 0 0]
[1 0 0 0]
[#x81 #xa9 #x56 #x53 #x54 #x2e #x6d #x61 #x67 #x69 #x63 #xce]
(bindat-pack '((data u32)) `((data . ,id)))
"PCHK"
(bindat-pack '((data u32r)) `((data . ,(+ 4 fxplen))))
[1 0 0 0]
fxp
))
(setq ret (concat
"NIKSNISI"
(bindat-pack '((data u32r)) `((data . ,(+ 4 nisilen))))
[1 0 0 0]
ret
))
;;save nksf file
(let ((file-coding-system-alist nil)
(coding-system-for-write 'binary))
(with-temp-file (concat nksf-path "/" vstname "/" presetname ".nksf")
(setq buffer-file-coding-system 'binary)
(set-buffer-multibyte nil)
(insert (concat
"RIFF"
(bindat-pack '((data u32r)) `((data . ,(length ret))))
ret
))))
)
;;; gen xrni for renoise
(defun create-xrni (fxp vstname devicefilename category presetname)
;;set category to "unbekannt"
(if (eq category "") (setq category "Unknown"))
;; read fxp file
(let ((coding-system-for-read 'binary))
(setq content (with-temp-buffer
(set-buffer-multibyte nil)
(setq buffer-file-coding-system 'binary)
(insert-file-contents fxp)
(buffer-string))))
;; strip fxp header
(setq content (base64-encode-string (substring content 60) t))
;; create xml
(setq content (concat "<?xml version=\"1.0\" encoding=\"UTF-8\"?><RenoiseInstrument doc_version=\"31\"><Name>"
presetname
"</Name><MidiInputProperties><Channel>-1</Channel><NoteRangeStart>0</NoteRangeStart><NoteRangeEnd>119</NoteRangeEnd><AssignedTrack>-1</AssignedTrack></MidiInputProperties><PluginGenerator><Channel>0</Channel><Transpose>0</Transpose><Volume>1.0</Volume><AutoSuspend>false</AutoSuspend><PluginDevice type=\"AudioPluginDevice\"><IsActive><Value>1.0</Value><Visualization>Device only</Visualization></IsActive><ActiveProgram>0</ActiveProgram><PluginType>VST</PluginType><PluginIdentifier>"
(substring devicefilename 0 -4)
"</PluginIdentifier><PluginDisplayName>"
vstname
"</PluginDisplayName><PluginShortDisplayName>"
vstname
"</PluginShortDisplayName><PluginEditorWindowPosition>-1,-1</PluginEditorWindowPosition><ParameterChunkType>Chunk</ParameterChunkType><ParameterChunk><![CDATA["
content
"]]></ParameterChunk></PluginDevice></PluginGenerator><ActiveGeneratorTab>Plugin</ActiveGeneratorTab></RenoiseInstrument>"))
;; write xml
(let ((file-coding-system-alist nil)
(coding-system-for-write 'binary))
(with-temp-file "Instrument.xml"
(setq buffer-file-coding-system 'binary)
(set-buffer-multibyte nil)
(insert content)))
;;pack xml
(call-process 7zip nil nil nil "a" "-tzip" (subst-char-in-string ?/ ?\\ (concat renoise-path "/" category "/" presetname ".xrni")) "Instrument.xml")
)
;;; gen metadata from basic file infos
(defun gen-bitwig-metadata (category fullfilepath filename vstname)
(setq tags '())
(setq cat category)
(setq creator "")
(setq bank "")
;; fix presetname
(setq presetname
(let ((case-fold-search nil))
(replace-regexp-in-string (concat "\\(" (string-join '(
"PAD"
"BASS"
"SYNTH"
"LEAD"
"FX"
"PLUCK"
) "\\|") "\\) - ") ""
(replace-regexp-in-string "^- \\(.+\\)$" "\\1"
(replace-regexp-in-string "^\\(.+\\) \[[A-Z0-9\]+\]$" "\\1"
(replace-regexp-in-string "^M[A-Z]L \\(.+\\)$" "\\1"
(replace-regexp-in-string "^[A-Z][A-Z] \\(.+\\)$" "\\1"
(replace-regexp-in-string "^[A-Z][A-Z] \\(.+\\) \[[A-Z0-9\]+\]$" "\\1" filename))))))))
;;set bank, if possible
(save-match-data
(and (string-match "/\\([a-zA-Z0-9 -]+\\).avxp/" fullfilepath)
(setq bank (match-string 1 fullfilepath))))
(save-match-data
(and (not (string-match "/Serum Presets/Presets/\\(Bass\\|Bass (Hard)\\|FX\\|Leads\\|Misc\\|Pads\\|Plucked\\|Seq\\|Synth\\)/" fullfilepath))
(string-match "/Serum Presets/Presets/\\([a-zA-Z0-9 -]+\\)/" fullfilepath)
(setq bank (match-string 1 fullfilepath))
))
;; fix categories
(let ((case-fold-search nil))
(cond
((and (string= category "Instruments") (string-match "^GT " filename)) (setq cat "Guitar"))
((and (string= category "Instruments") (string-match "^WW " filename)) (setq cat "Winds"))
((and (string= category "Instruments") (string-match "^MA " filename)) (setq cat "Chromatic Percussion"))
((and (string= category "Instruments") (string-match "^ST " filename)) (setq cat "Orchestral"))
((and (string= category "Instruments") (string-match "^IN " filename)) (setq cat "Orchestral"))
((and (string= category "Instruments") (string-match "^BR " filename)) (setq cat "Brass"))
((and (string= category "Instruments") (string-match "^BL " filename)) (setq cat "Bell"))
((string= category "Guitar") (setq cat "Guitar"))
((string= category "Winds") (setq cat "Winds"))
((string= category "Brass") (setq cat "Brass"))
((string= category "Leads") (setq cat "Lead"))
((string= category "Lead") (setq cat "Lead"))
((string= category "Trancegate") (progn (setq cat "Synth") (push "trancegate" tags)))
((string= category "Arps") (setq cat "Arps"))
((string= category "Arp") (setq cat "Arps"))
((string= category "Pianos") (setq cat "Piano"))
((string= category "Keyboards") (setq cat "Keyboards"))
((and (string= category "Piano & Keys") (string-match "^KB " filename)) (setq cat "Keyboards"))
((string= category "Piano & Keys") (setq cat "Piano"))
((string= category "Pads") (setq cat "Pad"))
((string= category "Pad") (setq cat "Pad"))
((string= category "Plucked") (setq cat "Plucks"))
((string= category "Plucks") (setq cat "Plucks"))
((string= category "Chords") (progn (setq cat "Synth") (push "chord" tags)))
((string= category "Effects") (setq cat "FX"))
((string= category "FX") (setq cat "FX"))
((string= category "Organ") (setq cat "Organ"))
((string= category "Bells") (setq cat "Bell"))
((string= category "Bell") (setq cat "Bell"))
((string= category "Drums") (setq cat "Drums"))
((string= category "Seq") (setq cat "Sequences"))
((string= category "Sequences") (setq cat "Sequences"))
((string= category "Synth") (setq cat "Synth"))
((string= category "Synths") (setq cat "Synth"))
((string= category "Voice") (progn (setq cat "Synth") (push "voice" tags)))
((string= category "Bass") (setq cat "Bass"))
((string= category "Bass (Hard)") (progn (setq cat "Bass") (push "hard" tags)))
((string= category "Modulated Bass") (progn (setq cat "Bass") (push "modulated" tags)))
((or (string= category "presets") (string= category "Presets") (string= category "User")) (setq cat "") (setq category ""))
((stringp category) (setq cat ""))
))
;; when no cat, but categoty is set, then it could be a presetpack
(if (and (string= cat "") (not (string= category "")))
(setq creator category))
(if (string= cat "")
(cond
((and (string-match "Bell" filename) (string-match "Piano" vstname)) (setq cat "Bell"))
((string-match "Piano" vstname) (setq cat "Piano"))))
;; when no category, check filename and gen one
(let ((case-fold-search nil))
(if (string= cat "")
(cond
((string-match "^SY " filename) (setq cat "Synth"))
((string-match "^SYNTH " filename) (setq cat "Synth"))
((string-match "^SQ " filename) (setq cat "Sequences"))
((string-match "^SEQ " filename) (setq cat "Sequences"))
((string-match "^FX " filename) (setq cat "FX"))
((string-match "^Fx " filename) (setq cat "FX"))
((string-match "^PD " filename) (setq cat "Pad"))
((string-match "^PAD " filename) (setq cat "Pad"))
((string-match "^BA " filename) (setq cat "Bass"))
((string-match "^BASS " filename) (setq cat "Bass"))
((string-match "^OR " filename) (setq cat "Organ"))
((string-match "^BL " filename) (setq cat "Bell"))
((string-match "^BS " filename) (setq cat "Brass"))
((string-match "^PL " filename) (setq cat "Plucks"))
((string-match "^PLUCK " filename) (setq cat "Plucks"))
((string-match "^PR " filename) (setq cat "Kick"))
((string-match "^KY " filename) (setq cat "Keyboards"))
((string-match "^LD " filename) (setq cat "Lead"))
((string-match "^LEAD " filename) (setq cat "Lead"))
((string-match "^ST " filename) (setq cat "Orchestral"))
((string-match "^SB " filename) (setq cat "Synth"))
((string-match "^WD " filename) (setq cat "Winds"))
((string-match "^VC " filename) (progn (setq cat "Synth") (push "voice" tags)))
((and (string-match "^OS " filename) (string-match "^ASL Soundlab" category)) (progn (setq cat "Bass") (push "oneshot" tags)))
((and (string-match "^MDL " filename) (string-match "^ASL Soundlab" category)) (progn (setq cat "Bass") (push "modulated" tags)))
((and (string-match "^MNL " filename) (string-match "^ASL Soundlab" category)) (setq cat "Bass"))
((string-match "Chord" filename) (progn (setq cat "Synth") (push "chord" tags)))
((string-match "Bell" filename) (setq cat "Bell"))
((string-match "Acid" filename) (setq cat "Bass"))
((string-match "Bass" filename) (setq cat "Bass"))
((string-match "303" filename) (setq cat "Bass"))
((string-match "Arp" filename) (setq cat "Arps"))
((string-match "Pluck" filename) (setq cat "Plucks"))
((string-match "Lead" filename) (setq cat "Lead"))
((string-match "Synth" filename) (setq cat "Synth"))
((string-match "String" filename) (setq cat "Pad"))
((string-match "AutoSeq" filename) (setq cat "Sequences"))
((string-match "Organ" filename) (setq cat "Organ"))
((string-match "PAD" filename) (setq cat "Pad"))
((string-match "Pad" filename) (setq cat "Pad"))
((string-match "ARP" filename) (setq cat "Arps"))
((string-match "SYN" filename) (setq cat "Synth"))
((string-match "SAX" filename) (setq cat "Winds"))
)))
;; add tags
(if (string-match "bright" filename) (push "bright" tags))
(if (string-match "dark" filename) (push "dark" tags))
(if (string-match "slow" filename) (push "slow" tags))
(if (string-match "fast" filename) (push "fast" tags))
(if (string-match "soft" filename) (push "soft" tags))
(if (string-match "hard" filename) (push "hard" tags))
(if (string-match "poly" filename) (push "poly" tags))
(if (string-match "chord" filename) (push "chord" tags))
(if (string-match "analog" filename) (push "analog" tags))
(if (string-match "digital" filename) (push "digital" tags))
(if (string-match "glide" filename) (push "glide" tags))
;; return data
`(
(presetname . ,presetname)
(category . ,cat)
(tags . ,(string-join
(remove-duplicates
tags)
" "))
(creator . ,creator)
(bank . ,bank)
))
(defun create-bitwig-preset (deviceid id2 devicename devicecreator presetname creator category tags comment fxpfile)
;;; header
(setq ret "")
;;; first meta chunk
(mapcar (lambda (el)
(if (string= (format "%s" (car el)) "_raw")
(setq ret (concat ret (cdr el)))
(setq ret
(if (listp (cdr el))
(concat
ret
(bindat-pack '((data u32)) `((data . 1)))
(bindat-pack '((data u32)) `((data . ,(string-width (format "%s" (car el))))))
(format "%s" (car el))
(cdr el))
(concat
ret
(bindat-pack '((data u32)) `((data . 1)))
(bindat-pack '((data u32)) `((data . ,(string-width (format "%s" (car el))))))
(format "%s" (car el))
(bindat-pack '((data u8)) `((data . 8)))
(bindat-pack '((data u32)) `((data . ,(string-width (cdr el)))))
(cdr el)))
)))
`(
(_raw . [0 0 0 4 0 0 0 4 ?m ?e ?t ?a])
(application_version_name . "1.3.15")
(branch . "release/1.3")
(comment . ,comment)
(creator . ,creator)
(device_category . "Synth")
(device_creator . ,devicecreator)
(device_id . ,(concat "vst:" (number-to-string deviceid) ":" (number-to-string id2)))
(device_name . ,devicename)
(device_type . "note_to_audio")
(preset_category . ,category)
(referenced_device_ids . (#x19 0 0 0 0))
(referenced_packaged_file_ids . (#x19 0 0 0 0))
(revision_id . "a017b4cd16e95f9efb2ecea10e2389f26fdb50d5")
(revision_no . (#x3 0 0 #xb9 #x65))
(tags . ,tags)
(type . "application/bitwig-preset")
(_raw . [0 0 0 0])
))
;;; fill it up with spaces, like in original presets, add non exists header
;; (setq ret (concat ret (make-string (- #x15fe (length ret) 1) #x20)))
(setq pos-chunk2 (length ret))
;;; second meta chunk
(mapcar (lambda (el)
(if (string= (format "%s" (car el)) "_raw")
(setq ret (concat ret (cdr el)))
(progn
(message (format "%s" (car (cdr el))))
(setq ret (concat ret (bindat-pack '((data u32)) `((data . ,(car el))))
(cond
((eq :bitwig-byte (car (cdr el))) (concat (string #x5) (string (cdr (cdr el)))))
((eq :bitwig-byte_2 (car (cdr el))) (concat (string #x1) (string (cdr (cdr el)))))
((eq :bitwig-u16 (car (cdr el))) (bindat-pack '((type u8) (data u16)) `((type . #x2) (data . ,(cdr (cdr el))))))
((eq :bitwig-u32 (car (cdr el))) (bindat-pack '((type u8) (data u32)) `((type . #x9) (data . ,(cdr (cdr el))))))
((eq :bitwig-empty-double (car (cdr el))) (bindat-pack '((type u8) (data u32) (data2 u32) (data3 u32)) `((type . #x7) (data . 0) (data2 . 0) (data3 . 0))))
((eq :bitwig-u32_2 (car (cdr el))) (bindat-pack '((type u8) (data u32)) `((type . #x3) (data . ,(cdr (cdr el))))))
((eq :bitwig-str (car (cdr el))) (concat (bindat-pack '((type u8) (data u32)) `((type . #x8) (data . ,(length (cdr (cdr el)))))) (cdr (cdr el))))
))))))
`(
;; chunk id
(_raw . [#xa 0 0 #x5 #x61])
;; unknown data
(#x1423 . (:bitwig-byte . 0))
(#x150a . (:bitwig-byte . 1))
(#x1421 . (:bitwig-u32 . #x1a5))
(#x2b9 . (:bitwig-str . ""))
;; presetname
(#x12de . (:bitwig-str . ,presetname))
;; devicename
(#x9a . (:bitwig-str . ,devicename))
;; unknown str
(#x1559 . (:bitwig-str . ""))
;; device creator
(#x9b . (:bitwig-str . ,devicecreator))
;; device type
(#x9c . (:bitwig-str . "Synth"))
;; unkown str
(#x9d . (:bitwig-byte_2 . 2))
;; preset creator
(#x9e . (:bitwig-str . ,creator))
;; comment
(#x9f . (:bitwig-str . ,comment))
;; category
(#xa1 . (:bitwig-str . ,category))
;; tags
(#xa2 . (:bitwig-str . ,tags))
;; big unkown data xD
(_raw . [ #x00 #x00 #x00 #xa3 #x05 #x01 #x00 #x00 #x13 #x7e #x05 #x01 #x00 #x00 #x0e #x31 #x12 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x30 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x31 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x32 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x33 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x34 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x35 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x36 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #xfb #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4d #x61 #x63 #x72 #x6f #x37 #x00 #x00 #x0e #x1c #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x24 #x09 #x00 #x00 #x00 #x85 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x41 #x4d #x4f #x55 #x4e #x54 #x00 #x00 #x01 #x36 #x07 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x42 #x09 #x00 #x00 #x02 #xfc #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x53 #x4f #x55 #x52 #x43 #x45 #x00 #x00 #x0e #x20 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x0e #x1d #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x03 #x00 #x00 #x17 #xcd #x0a #x00 #x00 #x0c #x5a #x09 #x00 #x00 #x02 #xb4 #x00 #x00 #x0c #x5b #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 ])
;; device id
(#xce4 . (:bitwig-u32_2 . ,deviceid ))
;; id2
(#xc5e . (:bitwig-u32_2 . ,id2))
;; fxp filename
(#xbe5 . (:bitwig-str . ,fxpfile))
;;last big unkown data
(_raw . [ #x00 #x00 #x13 #x18 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x14 #x1b #x01 #x00 #x00 #x00 #x14 #x1c #x01 #x22 #x00 #x00 #x14 #x1d #x05 #x01 #x00 #x00 #x14 #x1e #x05 #x01 #x00 #x00 #x13 #x7a #x09 #x00 #x00 #x03 #x7c #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x10 #xff #x0a #x00 #x00 #x00 #x00 #x00 #x00 #x13 #x7c #x09 #x00 #x00 #x04 #xf3 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x0d #x4f #x55 #x54 #x50 #x55 #x54 #x5f #x43 #x48 #x41 #x49 #x4e #x53 #x00 #x00 #x08 #xe0 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x14 #xfa #x09 #x00 #x00 #x02 #x4e #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x06 #x4f #x55 #x54 #x5f #x46 #x58 #x00 #x00 #x08 #xe1 #x09 #x00 #x00 #x01 #x8f #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x05 #x43 #x68 #x61 #x69 #x6e #x00 #x00 #x08 #xdf #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x03 #x49 #x09 #x00 #x00 #x00 #x33 #x00 #x00 #x02 #xb9 #x08 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x87 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 #x00 #x00 #x08 #x25 #x0a #x00 #x00 #x13 #x81 #x05 #x01 #x00 #x00 #x15 #x05 #x16 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x15 #x33 #x01 #x02 #x00 #x00 #x18 #x09 #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x14 #x22 #x12 #x00 #x00 #x00 #x03 #x00 #x00 #x00 #x00 ])
))
;;; get length of the current data for the new pk offset
(setq ret (concat "BtWg0001000200790000" (format "%04X" (+ 40 pos-chunk2)) "000000000000" (format "%04X" (+ 40 (length ret))) ret))
;;; delete old zip
(ignore-errors (delete-file (concat default-directory "plugin-states.zip")))
;;; generate new zip
(call-process 7zip nil nil nil "a" "-tzip" (subst-char-in-string ?/ ?\\ (concat default-directory "plugin-states.zip")) (subst-char-in-string ?/ ?\\ (concat default-directory "plugin-states")))
;;; read and append zip archive
(setq ret (concat ret (with-temp-buffer
(set-buffer-multibyte nil)
(setq buffer-file-coding-system 'binary)
(insert-file-contents-literally "plugin-states.zip")
(buffer-substring-no-properties (point-min) (point-max)))))
;;; write file to disk
(let ((file-coding-system-alist nil)
(coding-system-for-write 'binary))
(with-temp-file (concat bitwig-path "/Presets/" devicename "/" presetname ".bwpreset")
(setq buffer-file-coding-system 'binary)
(set-buffer-multibyte nil)
(insert ret))))
;;; create fxp patch from avgr patches
(defun create-fxp-avgr-preset (avgr fxp)
;; read file
(let ((coding-system-for-read 'binary))
(setq content (with-temp-buffer
(set-buffer-multibyte nil)
(setq buffer-file-coding-system 'binary)
(insert-file-contents avgr)
(buffer-string))))
;;; set some test data
(setq header (bindat-pack
;; vstspec
'((magiccode str 4)
(size u32)
(vstpatchtype str 4)
(version u32)
(pluginid str 4)
(pluginversion u32)
(parametercount u32)
(presetname strz 28)
(contentsize u32))
;; data
`((magiccode . "CcnK")
(size . ,(+ (length content) #x44))
(vstpatchtype . "FPCh")
(version . 1)
(pluginid . "Avgr")
(pluginversion . 1)
;; set a name from filename, respect the limit
(presetname . ,(substring (file-name-base avgr) 0 (min 27 (string-width (file-name-base avgr)))))
(parametercount . 0)
(contentsize . ,(length content)))
))
;;; write file to disk
(let ((file-coding-system-alist nil)
(coding-system-for-write 'binary))
(with-temp-file fxp
(setq buffer-file-coding-system 'binary)
(set-buffer-multibyte nil)
(insert (concat header content)))))
;;; init
(setq bitwig-path "H:/Bitwig Studio")
(setq 7zip "C:/Program Files/7-Zip/7z.exe")
(setq renoise-path "C:/Users/Andreas/Documents/Renoise/User Library/Instruments")
(setq nksf-path "C:/Users/Andreas/Documents/Native Instruments/User Content")
;;; central vst list to generate patches
(setq vstlist
`(
(
(id . #x58667358)
(id2 . 1108)
(vstname . "Serum")
(devicecreator . "Xfer Records")
(devicefilename . "Serum_x64.dll")
(presetspath . "C:/Users/Andreas/Documents/Xfer/Serum Presets/Presets")
(presettype . "fxp")
(xrni . nil)
(nksf . t)
)
;; (
;; (id . #x7a4a4175)
;; (id2 . 105)
;; (vstname . "JP6K")
;; (devicecreator . "SynthMaker")
;; (devicefilename . "JP6K.dll")
;; (presetspath . "H:/Programme/FXP Presets/JP6K")
;; (presettype . "fxp")
;; (xrni . nil)
;; (nksf . nil)
;; )
(
(id . #x53315673)
(id2 . 1)
(vstname . "Synth1 VSTi")
(devicecreator . "Daichi")
(devicefilename . "Synth1 VST64.dll")
(presetspath . "H:/Programme/FXP Presets/Synth1")
(presettype . "fxp")
(xrni . nil)
(nksf . t)
)
(
(id . #x5074356d)
(id2 . 581)
(vstname . "Pianoteq 5 STAGE")
(devicecreator . "Modartt")
(devicefilename . "Pianoteq 5 STAGE (64-bit).dll")
(presetspath . "C:/Users/Andreas/AppData/Roaming/Modartt/Pianoteq/Presets/My Presets")
(presettype . "fxp")
(xrni . nil)
(nksf . nil)
)
(
(id . #x41766772)
(id2 . 65568)
(vstname . "VPS Avenger")
(devicecreator . "Vengeance")
(devicefilename . "VPS Avenger_x64.dll")
(presetspath . "H:/Avengers")
(presettype . "avgr")
(xrni . nil)
(nksf . t)
)
)
)
;;; process all vsts
(mapcar (lambda (vst)
;; step through all presets and create btiwig patches for
(mapcar (lambda (filename)
;; gen metadata for bitwig patch
(setq metadata (gen-bitwig-metadata (nth 1 (reverse (split-string filename "/"))) filename (file-name-base filename) (cdr (assoc 'vstname vst))))
;; only generate bitwig patch, when its not exists
(if
(or
(not (file-exists-p (concat bitwig-path "/Presets/" (cdr (assoc 'vstname vst)) "/" (cdr (assoc 'presetname metadata)) ".bwpreset")))
(and
(not (file-exists-p (concat renoise-path "/" (cdr (assoc 'category metadata)) "/" (cdr (assoc 'presetname metadata)) ".xrni")))
(cdr (assoc 'xrni vst))
)
(and
(not (file-exists-p (concat nksf-path "/" (substring (cdr (assoc 'devicefilename vst)) 0 -4) "/" (cdr (assoc 'presetname metadata)) ".nksf")))
(cdr (assoc 'nksf vst))
)
)
(progn
;; prepare fxp patch, if needed
(cond
((string= (cdr (assoc 'presettype vst)) "fxp") (copy-file filename (concat default-directory "plugin-states/" (file-name-base filename) ".fxp")))
((string= (cdr (assoc 'presettype vst)) "avgr") (create-fxp-avgr-preset filename (concat default-directory "plugin-states/" (file-name-base filename) ".fxp")))
)
;;create nksf
(if
(and
(not (file-exists-p (concat nksf-path "/" (substring (cdr (assoc 'devicefilename vst)) 0 -4) "/" (cdr (assoc 'presetname metadata)) ".nksf")))
(cdr (assoc 'nksf vst))
)
(create-nksf
(concat default-directory (concat "plugin-states/" (file-name-base filename) ".fxp"))
(cdr (assoc 'id vst))
(cdr (assoc 'devicefilename vst))
(cdr (assoc 'devicecreator vst))
(cdr (assoc 'presetname metadata))
(cdr (assoc 'category metadata))
(cdr (assoc 'tags metadata))
(cdr (assoc 'bank metadata))
(concat "Preset generated from " filename)
))
;;create xrni
(if
(and
(not (file-exists-p (concat renoise-path "/" (cdr (assoc 'category metadata)) "/" (cdr (assoc 'presetname metadata)) ".xrni")))
(cdr (assoc 'xrni vst))
)
(create-xrni
(concat default-directory (concat "plugin-states/" (file-name-base filename) ".fxp"))
(cdr (assoc 'vstname vst))
(cdr (assoc 'devicefilename vst))
(cdr (assoc 'category metadata))
(cdr (assoc 'presetname metadata))))
;; create bitwig patch
(if (not (file-exists-p (concat bitwig-path "/Presets/" (cdr (assoc 'vstname vst)) "/" (cdr (assoc 'presetname metadata)) ".bwpreset")))
(create-bitwig-preset
(cdr (assoc 'id vst))
(cdr (assoc 'id2 vst))
(cdr (assoc 'vstname vst))
(cdr (assoc 'devicecreator vst))
(cdr (assoc 'presetname metadata))
(cdr (assoc 'creator metadata))
(cdr (assoc 'category metadata))
(cdr (assoc 'tags metadata))
(concat "Preset generated from " filename)
(concat (file-name-base filename) ".fxp")))
;; delete old fxp
(ignore-errors (delete-file (concat default-directory (concat "plugin-states/" (file-name-base filename) ".fxp"))))
)
)
)
(directory-files-recursively
(cdr (assoc 'presetspath vst))
(concat "\\." (cdr (assoc 'presettype vst)) "$"))
)
) vstlist)
(message "done!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment