desidulate is a suite of command line "decompiler" tools for transcribing and analyzing C64/SID music, based on Pandas.
desidulate works directly on SID register log files (those generated by VICE's -sounddev dump
option), which means it can parse music from any C64 software that VICE can run (game, demo, .sid file, etc).
desidulate is intended to help SID composers and musicologists understand the SID and SID instrument design process more quickly and completely, find unexplored territory, and build upon the SID music legacy. desidulate was also written to assist CHIME RED Tesla coil synthesizer research, and to provide training data for Magenta.
To install the most recent release:
$ pip install desidulate
To install a development release:
$ git clone https://github.com/anarkiwi/desidulate
$ pip install desidulate/
desidulate is intended to be used as a pipeline, where the input is a VICE emulator SID register dump, and the output could be WAVs, Simple MIDI Files (SMF), Pandas dataframes representing SID "instruments", or even entire performances for analysis.
The first task in the desidulate workflow, is to transcribe a VICE register log file, into desidulate SSFs (SID Sound Fragment) dataframes. A single SSF, represents all SID register changes made a SID voice (and its modulating voice frequency/test status, if ring or synchornization is used), in between the time the voice's GATE bit is changed from 0 to 1 (which starts the envelope generator).
desidulate reads the register log file and produces a dataframe with all SSFs, and another dataframe with a time based log, of when each SSF was triggered. An SSF may be triggered many times during a performance. desidulate eliminates redundant register writes (for example, where the same values are repeatedly written to the same registers).
In following examples, we are using VICE's vsid player (we could also use x64sc) to work with Cauldron_II_Remix.sid from the High Voltage SID Collection.
$ vsid -sounddev dump -soundarg C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.sid.dump -warp -limit 300000000 C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.sid
$ reg2ssf C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.sid.dump
reg2ssf identifies all SSFs (see above) and writes them to C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.ssf.zst
, and log file C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.log.zst
.
SSFs are output in order of frequency of occurence, most first:
$ zstdcat C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.ssf.zst |head
hashid,clock,pr_frame,gate1,freq1,pwduty1,pulse1,noise1,tri1,saw1,test1,sync1,ring1,freq3,test3,flt1,fltcoff,fltres,fltlo,fltband,flthi,fltext,atk1,dec1,sus1,rel1,vol,rate,pr_speed,hashid_noclock,count
-2174233589037180891,0,0,1,,,,,,,1,,,,,,,,,,,,0,2,10,0,15,19339,1,-6871201304917122305,286
-2174233589037180891,19689,1,1,53414,,0,1,0,0,0,,,,,0,,,,,,,,,,,15,19339,1,-6871201304917122305,286
-2174233589037180891,39399,2,1,5614,,0,1,0,0,0,,,,,0,,,,,,,,,,,15,19339,1,-6871201304917122305,286
-2174233589037180891,39421,2,0,5614,,0,0,1,0,0,,,,,0,,,,,,,,,,,15,19339,1,-6871201304917122305,286
-2174233589037180891,58738,3,0,2650,,0,0,1,0,0,,,,,0,,,,,,,,,,,15,19339,1,-6871201304917122305,286
-2174233589037180891,78605,4,0,2650,,0,0,1,0,0,,,,,0,,,,,,,,,,,15,19339,1,-6871201304917122305,286
-5281139747119741370,0,0,1,,,,,,,1,,,,,,,,,,,,0,2,14,0,15,19383,1,757979854999595997,193
$ ssf2midi C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.log.zst
ssf2midi generates a SMF file C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.mid
from reg2ssf log and ssf files (note only the path to the log file is specified).
desidulate will generate a multitrack SMF (one track for each voice, and an additional track for each voice for percussion). The intent is not perfect MIDI reproduction (not possible due to missing features in MIDI like standardized support for filter sweeps, and envelope durations etc) but to allow analysis of SID programming techniques (e.g. how a particular kick sound is made), and to allow a composer to have MIDI based devices accompany a C64 composition without complex hardware integration. Percussion detection is based on the use of the noise waveform, SSF duration, and initial pitch drop detection (SSFs that use noise exclusively, are assigned "hi hat" type sounds, and those SSFs that combine noise with other waveforms are variously assigned kick, snare or tom drums based on frequency). Velocity assignment is done by approximating the mean level of the envelope generator over the entire duration of the SSF.
$ ssf2wav C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.log.zst --hashid -5281139747119741370 --play
hashid pr_frame gate1 freq1 pwduty1 pulse1 noise1 tri1 saw1 test1 sync1 ring1 freq3 test3 flt1 fltcoff fltres fltlo fltband flthi fltext atk1 dec1 sus1 rel1 vol rate pr_speed hashid_noclock count real_freq closest_note
clock
0 -5281139747119741370 0 1 <NA> <NA> <NA> <NA> <NA> <NA> 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> 0 2 14 0 15 19383 1 757979854999595997 193 <NA> <NA>
19694 -5281139747119741370 1 1 50416 <NA> 0 1 0 0 0 <NA> <NA> <NA> <NA> 1 768 15 1 1 0 0 0 2 14 0 15 19383 1 757979854999595997 193 2960.697601 102
39063 -5281139747119741370 2 0 3537 2048 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 40 15 0 0 1 0 0 2 14 0 15 19383 1 757979854999595997 193 207.711588 56
58720 -5281139747119741370 3 0 2974 2048 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 16 15 0 1 1 0 0 2 14 0 15 19383 1 757979854999595997 193 174.649212 53
78378 -5281139747119741370 4 0 2974 2048 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 128 15 0 0 1 0 0 2 14 0 15 19383 1 757979854999595997 193 174.649212 53
Playing WAVE 'C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.wav' : Signed 16 bit Little Endian, Rate 11025 Hz, Mono
{'drum_instrument': 45, 'samples': 657, 'loudestf': 167, 'last_clock': 78378, 'initial_pitch_drop': 4}
Where --hashid
is the SSF to play. If not specified, all WAVs for all SSFs will be generated.
desidulate can, with some limitations, transcribe an SSF to a Sid Wizard instrument. desidulate attempts to optimize the transcribed instrument by detecting and automating filter and PWM curves.
- Generate WAVs for every SSF in a song:
$ ssf2wav C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.ssf.zst
-
Listen to the WAVs, to find the instrument you wish to transcribe, which will be indentified with a hashid in the filename.
-
Transcribe the SSF into an instrument (in this case, a kick sound):
$ ssf2swi C64Music/MUSICIANS/L/Linus/Cauldron_II_Remix.ssf.zst -1975247557004053752
multispeed: 1
ADSR: 05F0
F WFARP PULSE FILT
0 00 81BB .... BF60
1 01 41A7 88.. BF03
2 02 419B 84.. 02F8
3 03 .... 0340 BF12
4 04 .... 85.. BF06
5 05 .... 0340 BF02
6 06 .... 86.. BF03
7 07 .... 0240 ....
8 08 .... .... ....
9 09 .... .... ....
10 0A .... .... ....
11 0B .... .... ....
12 0C .... .... ....
gate1 freq1 pwduty1 pulse1 noise1 tri1 saw1 test1 sync1 ring1 freq3 test3 flt1 fltcoff fltres fltlo fltband flthi real_freq closest_note
0 1 7940 <NA> 0 1 0 0 0 <NA> <NA> <NA> <NA> 1 768 15 1 1 0 466.28 70
1 1 2501 2048 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 146.87 50
2 1 1250 1024 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 16 15 1 1 0 73.41 38
3 1 1250 1088 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 8 15 1 1 0 73.41 38
4 1 1250 1152 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 144 15 1 1 0 73.41 38
5 1 1250 1216 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 48 15 1 1 0 73.41 38
6 1 1250 1280 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 16 15 1 1 0 73.41 38
7 1 1250 1344 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 73.41 38
8 1 1252 1408 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 73.52 38
9 1 1254 1472 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 73.64 38
10 1 1256 1536 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 73.76 38
11 1 1254 1600 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 73.64 38
12 1 1252 1664 1 0 0 0 0 <NA> <NA> <NA> <NA> 1 24 15 1 1 0 73.52 38
- enter the values into SID Wizard (a direct SWI exporter is planned), and play the sound with "z!"