<div dir="ltr">On Wed, Jul 23, 2008 at 16:41, Darren Landrum <<a href="mailto:darren.landrum@sbcglobal.net">darren.landrum@sbcglobal.net</a>> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="Ih2E3d"><a href="mailto:gordonjcp@gjcp.net">gordonjcp@gjcp.net</a> wrote:<br>
> It's not XML, it's a sort of flat-text-ish thing with various keywords<br>
> for setting keys, keygroups, mutegroups and so on.<br>
><br>
> Having briefly skimmed the spec over lunch, I'm not in much of a<br>
> position to say how good it is, but it "looks right".<br>
><br>
> Essentially an SFZ file is a text file describing what to do with a<br>
> bunch of .wav or .ogg files. It's almost worryingly clueful.<br>
<br>
</div>It wasn't actually created by Cakewalk, but by a small company that<br>
Cakewalk had bought, and rather than closing up or quelching SFZ, they<br>
decided to keep it open. That's the story best as I was able to divine<br>
it, anyway. And now with the news that Tascam is discontinuing all<br>
Gigastudio-related development (<a href="http://www.filmmusicmag.com/?p=1738" target="_blank">http://www.filmmusicmag.com/?p=1738</a> and<br>
confirmed on the "Legacy" section of Tascam's web site:<br>
<a href="http://www.tascam.com/legacy;37,7.html" target="_blank">http://www.tascam.com/legacy;37,7.html</a>) it's possible that SFZ might<br>
become a new standard for sample libraries to use. Garritan is<br>
apparently releasing, or getting set to release, their libraries in SFZ now.<br></blockquote><div><br>Hi Darren! :-)<br><br>Note that Garritan/Plogue are using a later version of the SFZ format with additional and sometimes custom opcodes in their ARIA player. (See e.g. <a href="http://www.northernsounds.com/forum/showthread.php?t=60929">http://www.northernsounds.com/forum/showthread.php?t=60929</a> )<br>
<br>Here's a simple tokenizer for SFZ I wrote once upon a time in Python. Not sure if I got it completely right.<br><br>[BEGIN PYTHON]<br><br>import sys<br><br>def find_delimiter(string, delimiter):<br> """Find all occurences of delimiter."""<br>
start, i, ndx = 0, 0, []<br> while True:<br> i = string.find(delimiter, start)<br> if i != -1:<br> start = i + 1<br> ndx.append((i, delimiter))<br> else:<br> break<br>
return ndx<br><br>def find_all_delimiters(string, delimiters):<br> """Find all delimiters."""<br> ndx = []<br> for delimiter in delimiters:<br> ndx.extend(find_delimiter(string, delimiter))<br>
return ndx<br><br>def tokenize_sfz(string):<br> """Tokenize SFZ string."""<br> delimiters = [<br> # comments<br> '\n',<br> '//',<br> # headers<br>
'<region>',<br> '<group>',<br> # sample definition<br> 'sample=',<br> # input controls<br> 'lochan=', 'hichan=',<br> 'lokey=', 'hikey=', 'key=',<br>
'lovel=', 'hivel=',<br> 'lobend=', 'hibend=',<br> 'locahnaft=', 'hichanaft=',<br> 'lopolyaft=', 'hiplyaft=',<br> 'lorand=', 'hirand=',<br>
'lobpm=', 'hibmp=',<br> 'seq_length=', 'seq_position=',<br> 'sw_lokey=', 'sw_hikey=', 'sw_last=', 'sw_down=', 'sw_up=', 'sw_previous=', 'sw_vel=',<br>
'trigger=',<br> 'group=',<br> 'off_by=', 'off_mode=',<br> ] + [<br> 'on_locc%d=' % cc for cc in range(128)<br> ] + [<br> 'on_locc%d=' % cc for cc in range(128)<br>
] + [<br> # performance parameters<br> 'delay=', 'delay_random=',<br> ] + [<br> 'delay_cc%d=' % cc for cc in range(128)<br> ] + [<br> 'offset=', 'offset_random=', <br>
] + [<br> 'offset_cc%d=' % cc for cc in range(128)<br> ] + [<br> 'end=',<br> 'count=',<br> 'loop_mode=', 'loop_start=', 'loop_end=',<br>
'sync_beats=', 'sync_offset=', <br> # pitch<br> 'transpose=',<br> 'tune=',<br> 'pitch_keycenter=', 'pitch_keytrack=', 'pitch_veltrack=', 'pitch_random=',<br>
'bend_up=', 'bend_down=', 'bend_step=',<br> # pitch eg<br> 'pitcheg_delay=',<br> 'pitcheg_start=',<br> 'pitcheg_attack=',<br> 'pitcheg_hold=',<br>
'pitcheg_decay=',<br> 'pitcheg_sustain=',<br> 'pitcheg_release=',<br> 'pitcheg_depth=',<br> 'pitcheg_vel2delay=',<br> 'pitcheg_vel2attack=',<br>
'pitcheg_vel2hold=',<br> 'pitcheg_vel2decay=',<br> 'pitcheg_vel2sustain=',<br> 'pitcheg_vel2realease=',<br> 'pitcheg_vel2depth=', <br> # pitch lfo<br>
'pitchlfo_delay=',<br> 'pitchlfo_fade=',<br> 'pitchlfo_freq=',<br> 'pitchlfo_depth=', <br> ] + [<br> 'pitchlfo_depthcc%d=' % cc for cc in range(128)<br>
] + [<br> 'pitchlfo_depthchanaft=',<br> 'pitchlfo_depthpolyaft=', <br> ] + [<br> 'pitchlfo_freqcc%d=' % cc for cc in range(128)<br> ] + [<br> 'pitchlfo_freqchanaft=',<br>
'pitchlfo_freqpolyaft=',<br> # filter<br> 'fil_type=',<br> 'cutoff=', <br> ] + [<br> 'cutoff_cc%d=' % cc for cc in range(128)<br> ] + [<br>
'cutoff_chanaft=', 'cutoff_polyaft=',<br> 'resonance=',<br> 'fil_keytrack=', 'fil_keycenter=', 'fil_veltrack=', 'fil_random=',<br> # filter eg<br>
'fileg_delay=',<br> 'fileg_start=',<br> 'fileg_attack=',<br> 'fileg_hold=',<br> 'fileg_decay=',<br> 'fileg_sustain=',<br> 'fileg_release=',<br>
'fileg_depth=',<br> 'fileg_vel2delay=',<br> 'fileg_vel2attack=',<br> 'fileg_vel2hold=',<br> 'fileg_vel2decay=',<br> 'fileg_vel2sustain=',<br>
'fileg_vel2realease=',<br> 'fileg_vel2depth=',<br> # filter lfo<br> 'fillfo_delay=',<br> 'fillfo_fade=',<br> 'fillfo_freq=',<br> 'fillfo_depth=', <br>
] + [<br> 'fillfo_depthcc%d=' % cc for cc in range(128)<br> ] + [<br> 'fillfo_depthchanaft=',<br> 'fillfo_depthpolyaft=', <br> ] + [<br> 'fillfo_freqcc%d=' % cc for cc in range(128)<br>
] + [<br> 'fillfo_freqchanaft=',<br> 'fillfo_freqpolyaft=',<br> # amplifier<br> 'volume=',<br> 'pan=',<br> 'width=',<br> 'position=',<br>
'amp_keytrack=', 'amp_keycenter=', 'amp_veltrack=',<br> ] + [<br> 'amp_velcurve_%d=' % c for c in range(128)<br> ] + [<br> 'amp_random=',<br> 'rt_decay=',<br>
'output=',<br> ] + [<br> 'gain_cc%d=' % cc for cc in range(128)<br> ] + [<br> 'xfin_lokey=', 'xfin_hikey=',<br> 'xfout_lokey=', 'xfout_hikey=',<br>
'xf_keycurve=',<br> 'xfin_lovel=', 'xfin_hilev=',<br> 'xfout_lovel=', 'xfout_hilev=',<br> 'xf_velcurve=', <br> ] + [<br> 'xfin_locc%d=' % cc for cc in range(128)<br>
] + [<br> 'xfin_hicc%d=' % cc for cc in range(128)<br> ] + [<br> 'xfout_locc%d=' % cc for cc in range(128)<br> ] + [<br> 'xfout_hicc%d=' % cc for cc in range(128)<br>
] + [<br> 'xf_cccurve=',<br> # amplifier eg<br> 'ampeg_delay=',<br> 'ampeg_start=',<br> 'ampeg_attack=',<br> 'ampeg_hold=',<br> 'ampeg_decay=',<br>
'ampeg_sustain=',<br> 'ampeg_release=',<br> 'ampeg_vel2delay=',<br> 'ampeg_vel2attack=',<br> 'ampeg_vel2hold=',<br> 'ampeg_vel2decay=',<br>
'ampeg_vel2sustain=',<br> 'ampeg_vel2release=',<br> ] + [<br> 'ampeg_delaycc%d=' % cc for cc in range(128)<br> ] + [<br> 'ampeg_startcc%d=' % cc for cc in range(128)<br>
] + [<br> 'ampeg_attackcc%d=' % cc for cc in range(128)<br> ] + [<br> 'ampeg_holdcc%d=' % cc for cc in range(128)<br> ] + [<br> 'ampeg_decaycc%d=' % cc for cc in range(128)<br>
] + [<br> 'ampeg_sustaincc%d=' % cc for cc in range(128)<br> ] + [<br> 'ampeg_releasecc%d=' % cc for cc in range(128)<br> ] + [<br> # amplifier lfo<br> 'amplfo_delay=',<br>
'amplfo_fade=',<br> 'amplfo_freq=',<br> 'amplfo_depth=', <br> ] + [<br> 'amplfo_depthcc%d=' % cc for cc in range(128)<br> ] + [<br> 'amplfo_depthchanaft=',<br>
'amplfo_depthpolyaft=', <br> ] + [<br> 'amplfo_freqcc%d=' % cc for cc in range(128)<br> ] + [<br> 'amplfo_freqchanaft=',<br> 'amplfo_freqpolyaft=',<br>
# equalizer<br> 'eq1_freq=', 'eq2_freq=', 'eq3_freq=', <br> ] + [<br> 'eq1_freqcc%d=' % cc for cc in range(128)<br> ] + [<br> 'eq2_freqcc%d=' % cc for cc in range(128)<br>
] + [<br> 'eq3_freqcc%d=' % cc for cc in range(128)<br> ] + [<br> 'eq1_vel2freq', 'eq2_vel2freq', 'eq3_vel2freq',<br> 'eq1_bw', 'eq2_bw', 'eq3_bw', <br>
] + [<br> 'eq1_bwcc%d=' % cc for cc in range(128)<br> ] + [<br> 'eq2_bwcc%d=' % cc for cc in range(128)<br> ] + [<br> 'eq3_bwcc%d=' % cc for cc in range(128)<br>
] + [<br> 'eq1_gain=', 'eq2_gain=', 'eq3_gain=', <br> ] + [<br> 'eq1_gaincc%d=' % cc for cc in range(128)<br> ] + [<br> 'eq2_gaincc%d=' % cc for cc in range(128)<br>
] + [<br> 'eq3_gaincc%d=' % cc for cc in range(128)<br> ] + [<br> 'eq1_vel2gain=', 'eq2_vel2gain=', 'eq3_vel2gain=',<br> # effects<br> 'effect1=', 'effect2=', <br>
]<br> stack = find_all_delimiters(string, delimiters)<br> stack.sort()<br> stack.reverse()<br> comment = False<br> tokens = []<br> while True:<br> try:<br> start = stack.pop()<br>
end = stack.pop()<br> stack.append(end)<br> except IndexError:<br> break<br> if start[1] == '//':<br> comment = True<br> elif start[1] == '\n':<br>
comment = False<br> continue<br> if not comment:<br> tokens.append(sfz[start[0]:end[0]].rstrip().split('=', 1))<br> return tokens<br><br><br>sfzf = open(sys.argv[1], 'r')<br>
sfz = sfzf.read()<br>sfzf.close()<br>print tokenize_sfz(sfz)<br><br>[END PYTHON]<br></div></div><br>-- <br>Anders Dahnielson<br><<a href="mailto:anders@dahnielson.com">anders@dahnielson.com</a>>
</div>