<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>