1) Stop using the "1GrandPiano" sample set.
Just look at this:
Sound of silence |
The samples in the "1GrandPiano" set have varying lengths of silence before the sample starts. The silence is often just 10ms but on some samples it is up to 50ms.
If you have fought with latency issues before, you know that 50ms is a lot. It will make playing really hard. But what's even worse than a stable 50ms latency is that these samples have different lengths of silence before them. That makes the latency seem random and is really awful to play.
This sample set was one of the first introduced on the Samplerbox site. I think it was there from the beginning. So when I read complaints about latency with Samplerbox, I get the feeling that the cause is actually this sample set in most cases.
If you really want to use this sample set, you could trim the silence out of the samples. Some years ago I made a python script to do just this.
Disclaimer: I was just learning python at the time, so the code is probably not very pythonic. But it worked for me.
Note that it will cut silence and also a part of the attack! The higher the threshold value, the more you will cut from the beginning of the sample.
It will also cut any silence after the sample. That will make the sample set much smaller and thus faster to load.
Have fun.
# Sample trimmer for Python 3.x # by Juho-Eric # 24.10.2016 # # This script trims silence out from the beginning of wave files. # It makes them respond better when played live (reduces latency) and # makes the file size smaller by removing the unnecessary silence. # # The script looks for .wav files in this directory and creates # a subdirectory "trimmed" that contains the trimmed version of each # sample. # import glob import os import wave import struct import timeit def getframe(frames, i): framelong = frames[4*i]+(frames[4*i+1]<<8)+(frames[4*i+2]<<16)+(frames[4*i+3]<<24) framebs = struct.pack('L', framelong) return struct.unpack("<hh",framebs) def setframe(frames, f, l, r): framebs = struct.pack('<hh', int(l), int(r)) a,b,c,d = struct.unpack('BBBB',framebs) frames[f*4] = a frames[f*4+1] = b frames[f*4+2] = c frames[f*4+3] = d return # Just for checking how much time it takes to run scriptstart = timeit.default_timer() startthreshold = 100 endthreshold = 10 fadeinlength = 4 fadeoutlength = 4 wavefiles = glob.glob("*.wav") totalcutframes = 0 totalcutsecs = 0 # Make output directory if not made yet try: os.stat("trimmed") except: os.mkdir("trimmed") # Go through all wave files in this directory for file in wavefiles: win = wave.open(file, 'r') params = win.getparams() #nbits = win.getsampwidth()*8 #nchannels = win.getnchannels() nframes = win.getnframes() framerate = win.getframerate() # File is opened for reading. #print("Opening "+file+": "+str(nchannels)+" channels "+str(nbits)+"-bit "+str(framerate)+" Hz") # Get all frames as bytearray. frames = bytearray(win.readframes(nframes)) # Find the first point where threshold is broken (trim starting silence) framewas = 0 for i in range(nframes-1): l,r = getframe(frames, i) if (abs(l) > startthreshold or abs(r) > startthreshold): framewas = i break startframe = framewas startsecs = startframe / framerate totalcutsecs += startsecs totalcutframes += startframe print(file +" cut from start "+str(startframe)+" frames / "+str(startsecs)+" s") # Find the frame where the silence starts again (trim ending silence) framewas = nframes for i in range(nframes-1, 0, -1): l,r = getframe(frames, i) if (abs(l) > endthreshold or abs(r) > endthreshold): framewas = i break endframe = framewas cutendframes = nframes - endframe cutendsecs = cutendframes / framerate totalcutsecs += cutendsecs totalcutframes += cutendframes print(file+" cut from end "+str(cutendframes)+" frames / "+str(cutendsecs)+" s") # Create fadein for i,f in enumerate(range(startframe,startframe+fadeinlength)): l,r = getframe(frames,f) multiplier = ((i+1)/(fadeinlength+1)) setframe(frames, f, l*multiplier, r*multiplier) # Create fadeout for i,f in enumerate(range(endframe-fadeoutlength,endframe)): l,r = getframe(frames,f) multiplier = ((fadeoutlength-i)/(fadeoutlength+1)) setframe(frames, f, l*multiplier, r*multiplier) # write output file wout = wave.open("trimmed/"+file, 'w') wout.setparams(params) wout.writeframes(frames[startframe*4:endframe*4]) wout.close() win.close() print("Total: cut "+str(totalcutframes)+" frames / "+str(totalcutsecs)+" s") scriptstop = timeit.default_timer() print("Operation took "+str(scriptstop-scriptstart)+" seconds")