This adds a new articulation for the string sections. It corresponds to the technique known as "artificial harmonics". In this technique, you finger a note you want to play, then use your fourth finger to lightly touch the string at a position corresponding to the note a perfect fourth higher. It damps all the harmonics that don't have a node at that point. The result is a tone two octaves higher than the note you fingered with a thin, ghostly sound.
It's easy to create the same effect digitally. I started from the sustain samples and applied a set of notch filters to reduce all the harmonics that should be damped.
I didn't want to have to loop all the new samples by hand, so I just reused the loop points from the original samples and blended the transitions. This worked well for all the instruments except basses, which had more pronounced artifacts from looping. Rather than try to deal with them, I decided to just omit them. That's realistic: artificial harmonics are very difficult to play on a bass and are rarely used (although a related technique called "natural harmonics" does get used).
For posterity, here is the script I used to create the samples.
import numpy as np
import scipy.io
import soundfile
import struct
import sys
import os
noteNames = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b']
path = sys.argv[1]
def readLoopPoints(name):
with open(os.path.join(path, name), 'rb') as input:
fsize, is_big_endian = scipy.io.wavfile._read_riff_chunk(input)
while (input.tell() < fsize):
chunk_id = input.read(4)
if chunk_id == b'smpl':
input.read(32)
numloops = struct.unpack('<i', input.read(4))[0]
assert numloops >= 1
input.read(12)
start, end = struct.unpack('<ii', input.read(8))
return start, end
else:
scipy.io.wavfile._skip_unknown_chunk(input, is_big_endian)
assert False
def processSample(name, note_index):
sample_rate, samples = scipy.io.wavfile.read(os.path.join(path, name))
loop_start, loop_end = readLoopPoints(name)
samples = samples/32767
fc = sample_rate/2
spectrum_size = len(np.fft.rfft(samples[:,0]))
f0 = 440.0 * 2**((note_index-69)/12.0)
filter = np.ones(spectrum_size, dtype=np.float32)
notch_width = int((f0/fc)*spectrum_size/2)
notch = 0.5+0.5*np.cos(np.linspace(0, 2*np.pi, notch_width))
i = 1
while True:
freq = i*f0
center = int((freq/fc)*spectrum_size)
notch_start = center-notch_width//2
notch_end = notch_start+notch_width
if notch_end >= len(filter):
break
if i%4 == 0:
filter[notch_start:notch_end] = 2-notch
else:
depth = 0.98**i
filter[notch_start:notch_end] = (1-depth)+depth*notch
i += 1
result = []
for i in range(samples.shape[1]):
s = np.fft.irfft(np.fft.rfft(samples[:,i])*filter)
overlap = min(1000, int(20*sample_rate/f0))
blend = np.linspace(0.0, 1.0, overlap)
s[loop_end-overlap:loop_end] = blend*s[loop_start-overlap:loop_start] + (1-blend)*s[loop_end-overlap:loop_end]
result.append(s)
result = np.array(result).T
output_path = os.path.join(path, name.replace('sus', 'hrm').replace('wav', 'flac'))
soundfile.write(output_path, result, sample_rate)
for name in os.listdir(path):
if not name.endswith('.wav'):
continue
fields = name[:-4].split('-')
if fields[-2] != 'sus':
continue
octave = int(fields[-1][-1])
note = fields[-1][:-1]
note_index = noteNames.index(note)+(octave+1)*12
processSample(name, note_index)
This adds a new articulation for the string sections. It corresponds to the technique known as "artificial harmonics". In this technique, you finger a note you want to play, then use your fourth finger to lightly touch the string at a position corresponding to the note a perfect fourth higher. It damps all the harmonics that don't have a node at that point. The result is a tone two octaves higher than the note you fingered with a thin, ghostly sound.
It's easy to create the same effect digitally. I started from the sustain samples and applied a set of notch filters to reduce all the harmonics that should be damped.
I didn't want to have to loop all the new samples by hand, so I just reused the loop points from the original samples and blended the transitions. This worked well for all the instruments except basses, which had more pronounced artifacts from looping. Rather than try to deal with them, I decided to just omit them. That's realistic: artificial harmonics are very difficult to play on a bass and are rarely used (although a related technique called "natural harmonics" does get used).
For posterity, here is the script I used to create the samples.