Tips for writing an SFZ file

Link to good samples/soundfonts at http://wiki.linuxaudio.org/wiki/free_audio_data

Moderators: MattKingUSA, khz

Post Reply
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 357 times

Tips for writing an SFZ file

Post by j_e_f_f_g »

I ran across a post I made awhile back, and I figured that it may be useful to extract that info and see if raboof can make it a sticky topic so that it isn't buried where people can't find it.

Tips for writing an SFZ file

Someone asked me how to write an SFZ file where the closed hihat sound automatically cuts off any open hihat sound.

In a nutshell, if you want the playback of a set of waves to cutoff another set of waves, you put all the first set waves into one group and give them a group number (with the group opcode), then use the off_by opcode with the second set.

For example, a closed hihat hit, as well as a pedal close, cut off any open hihat (whether half open, or fully open) sound.

Therefore, your closed hihat waves, and any closed pedal waves must have a group number. Your open hihat waves must have an off_by with that group number.

Code: Select all

<region> sample=Closed_Hihat.wav group=1
<region> sample=Closed_Pedal.wav group=1
<region> sample=Full_Open_Hihat.wav off_by=1
<region> sample=Half_Open_Hihat.wav off_by=1

If you want the sound to be slowly cutoff (versus immediately cutoff) also use off_mode=normal. Otherwise, the sound will be cutoff immediately (which is what you want for cutting off open hihat).

Code: Select all

<region> sample=Closed_Hihat.wav group=1
<region> sample=Closed_Pedal.wav group=1
<region> sample=Full_Open_Hihat.wav off_by=1 off_mode=normal
<region> sample=Half_Open_Hihat.wav off_by=1 off_mode=normal

Just for clarification, let's review some of the ways that you can "qualify" (ie, apply certain rules during playback to) the triggering of a wave.

If you want the waves to play only for a specific range of notes (numbers), use the lokey and hikey opcodes.

Code: Select all

<region> sample=w1.wav lokey=60 hikey=60 /* Play only for note 60 */
<region> sample=w2.wav lokey=30 hikey=31 /* Play only for notes 30 and 31 */

If you want the waves to play only for notes on a specific midi channel, but not other midi channels, use the lochan and hichan opcodes.

Code: Select all

<region> sample=w1.wav lochan=1 hichan=4 /* Play only for notes on chan 1 to 4 */
<region> sample=w2.wav lochan=10 hichan=10 /* Play only on chan 10 (General MIDI drum chan) */

If you want the waves to play only when a note is within a specific volume range, use the lovel and hivel opcodes.

Code: Select all

<region> sample=w1.wav lovel=1 hivel=30 /* Play only notes at a volume 1 to 30 */
<region> sample=w1.wav lovel=31 hivel=127 /* Play only notes at a volume greater than 30 */

If you want the waves to play only when a specific midi controller is a certain value, use the locc and hicc opcodes. Follow the cc with the controller number you desire. For example, if you want mod wheel, follow cc with 1. If you want sustain pedal, follow cc with 64. Etc.

Code: Select all

<region> sample=w1.wav locc1=100 hicc1=127 /* Play only when mod wheel is between 100 to 127 */
<region> sample=w1.wav locc64=1 hicc64=127 /* Play only when the sustain pedal is on */

If you want the waves to play only when another specific midi note is or was held down (ie, commonly referred to as "key switching"). Use the sw_lokey and sw_hikey opcodes, along with either the sw_last, sw_down, or sw_up opcode.

For example, assume you have 3 sets of waves, for 3 different kits. You have a snare sound for kit 1 (Kit1_Snare.wav), a different snare sound for kit 2 (Kit2_Snare.wav), and another snare sound for kit 3 (Kit3_Snare.wav). You're going to assign all 3 snare waves to note 38.

You decide to use midi notes 24, 25, and 26 to switch between the kits. After you press note 24, all subsequent notes will play kit 1's snare. After you press note 25, all subsequent note will play kit 2's snare. After 26, it's kit 3.

First you need to specify that notes 24 to 26 are being used to switch sounds. You do that with the sw_lokey and sw_hikey opcodes. Here you use sw_lokey=24 and sw_hikey=26. These 2 opcodes need to be added to all regions. Then you can add either a sw_last, sw_down, or sw_up opcode to each region. For example, sw_last means "in the range sw_lokey to sw_hikey, which note in that range was last played".

Here we use sw_last to implement our snare switch.

Code: Select all

/* Play Kit1_Snare if key 24 (out of 24, 25, and 26) was last played */
<region> sample=Kit1_Snare.wav lokey=38 hikey=38 sw_last=24 sw_lokey=24 sw_hikey=26
/* Play Kit2_Snare if key 25 (out of 24, 25, and 26) was last played */
<region> sample=Kit2_Snare.wav lokey=38 hikey=38 sw_last=25 sw_lokey=24 sw_hikey=26
/* Play Kit3_Snare if key 26 (out of 24, 25, and 26) was last played */
<region> sample=Kit3_Snare.wav lokey=38 hikey=38 sw_last=26 sw_lokey=24 sw_hikey=26

And of course, you can combine any or all of the above ways (opcodes) to determine when a region gets triggered (played):

Code: Select all

/* Play only when note 60 plays, and the mod wheel is set between 100 and 127 */
<region> sample=w1.wav locc1=100 hicc1=127 lokey=60 hikey=60

If you have dozens and dozens of waves, you can save yourself a lot of typing by putting waves with the same opcode values under their own <group> header (not to be confused with the aforementioned group opcode. These two things are for different purposes. They just unfortunately are named similarly).

For example, assume you have lot of regions with the opcode values lovel=1 and hivel=30. And you have lots of other regions with lovel=31 and hivel=127. You could add those opcodes to each region like so:

Code: Select all

<region> sample=SnareVel1.wav lokey=38 hikey=38 lovel=1 hivel=30
<region> sample=SnareVel2.wav lokey=38 hikey=38 lovel=31 hivel=127
<region> sample=KickVel1.wav lokey=36 hikey=36 lovel=1 hivel=30
<region> sample=KickVel2.wav lokey=36 hikey=36 lovel=31 hivel=127
<region> sample=CrashVel1.wav lokey=57 hikey=57 lovel=1 hivel=30
<region> sample=CrashVel2.wav lokey=57 hikey=57 lovel=31 hivel=127

But you save some typing by separating all the lovel=1 hivel=30 regions into their own <group> section, and then specify the lovel=1 hivel=30 opcodes on the group itself. When you do this, those group opcodes get automatically applied to all the regions under it. You can do likewise with the lovel=31 hivel=127 regions, like so:

Code: Select all

<group> lovel=1 hivel=30 
/* All regions below play only for notes with a vol between 1 and 30 */
<region> sample=SnareVel1.wav lokey=38 hikey=38
<region> sample=KickVel1.wav lokey=36 hikey=36
<region> sample=CrashVel1.wav lokey=57 hikey=57

<group> lovel=31 hivel=127 
/* All regions below play only for notes with a vol between 31 and 127 */
<region> sample=SnareVel2.wav lokey=38 hikey=38
<region> sample=KickVel2.wav lokey=36 hikey=36
<region> sample=CrashVel2.wav lokey=57 hikey=57

There are so many more opcodes you can add to <region> (and <group>) to affect the playback of waves that it would probably be easier to know what specific behavior you're trying to model, and then look for the specific opcodes to use for that purpose.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

Post Reply