Skip to content

Commit

Permalink
Create sympathetic_resonance.md
Browse files Browse the repository at this point in the history
Very initial version, just writing stuff down while it's fresh in my mind.
  • Loading branch information
DSmolken authored Feb 26, 2025
1 parent 51c8cfb commit 414feed
Showing 1 changed file with 187 additions and 0 deletions.
187 changes: 187 additions & 0 deletions docs/tutorials/sympathetic_resonance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
title: Sympathetic Resonance
---

## Basics

Many instruments have elements which will resonate after a note is stopped. A piano
with the sustain pedal down is an obvious example. In sampled instruments, this is
usually dealt with by recording one set of pedal-up samples and one set of
pedal-down samples. Some sampled pianos will also support half-pedaling, though this
will have to be documented later.

The current version of this tutorial is based on an implementation of sympathetic
resonance for a nyckelharpa, which is, more or less, a violin with a key mechanism
and a set of 12 sympathetic strings. This was also reused for another instrument
with a smaller number of diatonic sympathetic strings.

The basic concept is simple: when a sustained note ends, a sympathetic resonance
sample is played as a release sample. In the case of the nyckelharpa, the resonance
samples were created by using only the tails of short notes. There is a set of
round robin samples for each pitch, and they are mapped to the keys as normal.

```sfz
<master>
#include "modules/maps/strings/nh/nh_sus_f_map.sfz"
<master>
trigger=release
ampeg_attack=0.1
#include "modules/maps/strings/nh/nh_release_map.sfz"
```

Instead of creating a separate set of samples it's even possible to simply use the
shorts samples with an offset, if the shorts are performed consistently enough.

```sfz
<master>
#include "modules/maps/strings/nh/nh_sus_f_map.sfz"
<master>
trigger=release
ampeg_attack=0.1
offset=6600
#include "modules/maps/strings/nh/nh_short_map.sfz"
```

## Controls

We can add a simple volume control.

```sfz
<master>
#include "modules/maps/strings/nh/nh_sus_f_map.sfz"
<master>
trigger=release
ampeg_attack=0.1
amplitude_oncc52=100
locc52=1
#include "modules/maps/strings/nh/nh_release_map.sfz"
```

To prevent the buildup of voices with fast playing, a polyphony group can be
used.

```sfz
<master>
#include "modules/maps/strings/nh/nh_sus_f_map.sfz"
<master>
trigger=release
ampeg_attack=0.1
amplitude_oncc52=100
locc52=1
off_time=0.4
group=14
note_polyphony=1
#include "modules/maps/strings/nh/nh_release_map.sfz"
```

## Multiple articulations

There could be a separate set of resonance samples captured for each technique, but
in practice one set of samples cut from shorts works reasonably well for most.
However, tremolo seemed to agitate all the strings more. In other words, playing an
A didn't just make the A and a little E resonate, even the A# and G# strings
resonated a bit, perhaps as a result of the whole instrument shaking a bit. So,
tremolo got its own set of samples.

Shorts and pizzicato didn't use separate resonance samples, they were simply set
to one-shot mode, so the entire sample played, resonance and all. This has its
downsides, of course, but again it seems to work well enough in reality.

However, with the jete technique, the same set of samples was used with the
addition of rt_decay. Keeping it simple, here is the polyphonic implementation:

```sfz
<master>
#include "modules/maps/strings/nh/nh_jete_map.sfz"
<master>
trigger=release
off_time=0.4
rt_decay=12
ampeg_attack=0.1
#include "modules/maps/strings/nh/nh_release_map.sfz"
```

## Legato

The above works fine for polyphonic instruments, but with a mono instrument it's
not enough to have a sample play on release; we also need to play a sample when
a note is muted and a new note starts playing. At that point, we need to trigger
the resonance based not on the incoming MIDI note but based on the previous pitch
that was playing.

```sfz
//Mono mode
<master>
group=1
off_by=1
#include "modules/maps/strings/nh/nh_sus_f_map.sfz"
//Mono mode, keypress restrictions so only triggered on last note of phrase
<master>
trigger=release
amplitude_oncc52=200
locc52=1
off_time=0.4
ampeg_attack=0.1
group=14
note_polyphony=1
//Trigger only when one key was down
lohdcc153=0
hihdcc153=1.1
//To keep from over-triggering when unison is on
group=199
note_polyphony=1
#include "modules/maps/strings/nh/nh_release_map.sfz"
//Mono mode, legato triggers
//Loop mode is one shot to keep these from dying when the next key is released
<master>
trigger=legato
amplitude_oncc52=200
locc52=1
locc105=64
off_time=0.4
ampeg_attack=0.1
loop_mode=one_shot
pitch_keytrack=0
#include "modules/maps/strings/nh/nh_release_swdown_map.sfz"
```

## Multiple voices

When one key triggers multiple samples, whether they are crossfaded dynamic layers,
mic posotions or unison voices, each sample playing is a voice which can trigger
a release. In other words, with four mic positions having four sets of releases,
sixteen release voices would be triggered for each note. This not only uses up
unison voices but also is too loud and doesn't sound good. Fortunately this is
easily fixed by creating a separate polyphony group for each voice's releases,
and limiting its note polyphony. If groups are already created as discussed above,
just make sure each set of samples has its own group number.

This is not a consideration limited to sympathetic resonance, of course, but a
general principle of using release triggers with multiple voices.

```sfz
<master>
trigger=release
ampeg_attack=0.1
//To keep from over-triggering when unison is on
group=199
note_polyphony=1
#include "modules/maps/strings/nh/nh_release_map.sfz"
```

## Other methods

At least in theory, a better way to do this would be to capture an impulse response
of the resonance, perhaps by giving the instrument a whack and letting the
sympathetic strings ring. However, this would require an sfz player with
convolution reverb implemented.

0 comments on commit 414feed

Please sign in to comment.