Skip to content

Commit

Permalink
Correct WT and Window handling og 16 full range wt files
Browse files Browse the repository at this point in the history
wt files with full-range 16 bit ints (so 16-is-16 or flag
0x8 + 0x4 = 0xC) was broken in a couple of ways, but most
importnatly, didn't survive a save/restore roundtrip.

This fixes it in three ways

1. When converting 16-as-16 to float scale accordingly with
   a different function and leave the ints untouched
2. Modify the window oscillator so if it gets a 16-as-16 it
   reduces the height of the ints to be consistent with a
   15 with an extra shift, making I15 WT vs Window and
   I16 WT vs Window consistent
3. Make sure it streams properly. No change required but
   tested.

Addresses surge-synthesizer#7694

Update wt-tool to allow int16 and int15 options both
  • Loading branch information
baconpaul committed Jul 10, 2024
1 parent 7a641fe commit 2d4cde0
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 16 deletions.
23 changes: 16 additions & 7 deletions scripts/wt-tool/wt-tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def read_wt_header(fn):
flags = {}
flags["is_sample"] = (fl[0] & 0x01 != 0)
flags["loop_sample"] = (fl[0] & 0x02 != 0)
flags["format"] = "int16" if (fl[0] & 0x04 != 0) else "float32"

flags["format"] = "int16-full-range" if (fl[0] == 0xC) else "int16" if (fl[0] & 0x04 != 0) else "float32"
flags["samplebytes"] = 2 if (fl[0] & 0x04 != 0) else 4

header["flags"] = flags
Expand Down Expand Up @@ -74,7 +75,7 @@ def explode(fn, wav_dir):
wav_file.writeframes(bdata)


def create(fn, wavdir, norm):
def create(fn, wavdir, norm, intform):
onlyfiles = [f for f in listdir(wavdir) if (isfile(join(wavdir, f)) and f.endswith(".wav"))]
onlyfiles.sort()

Expand Down Expand Up @@ -122,8 +123,8 @@ def create(fn, wavdir, norm):
newrec[2 * i + 1] = nms
newdb.append(newrec)
databuffer = newdb
elif (norm == "peak"):
print("Normalizing to peak")
elif (norm == "peak" or norm == "peak16"):
print("Normalizing to " + norm)
peakp = 0
peakm = 0
for d in databuffer:
Expand All @@ -141,6 +142,11 @@ def create(fn, wavdir, norm):
peakp = -peakm
print("Peak value is ", peakp)
newdb = []

den = 16384.0
if (norm == "peak16"):
den = den * 2

for d in databuffer:
newrec = bytearray(len(d))

Expand All @@ -149,7 +155,7 @@ def create(fn, wavdir, norm):
ms = d[2 * i + 1]
if(ms >= 128):
ms -= 256
r = int((ls + ms * 256) * 16384.0 / peakp)
r = int((ls + ms * 256) * den / peakp)

nls = int(r % 256)
nms = int(r / 256)
Expand All @@ -169,7 +175,7 @@ def create(fn, wavdir, norm):
outf.write(b'vawt')
outf.write(nf.to_bytes(4, byteorder='little'))
outf.write((len(onlyfiles)).to_bytes(2, byteorder='little'))
outf.write(bytes([4, 0]))
outf.write(bytes([4 if (intform == "i15") else 12, 0]))
for d in databuffer:
outf.write(d)

Expand Down Expand Up @@ -199,7 +205,10 @@ def main():
Modes are 'none' leave input untouched;
'half' input wav are divided by 2 (so 2^16 range becomes 2^15 range);
'peak' input wav are scanned and re-peaked to 2^15.
'peak16' input wav are scanned and re-peaked to 2^15.
""")
parser.add_option("-i", "--int-range", dest="intrange", default="i15", metavar="INTRANGE",
help = "Int range for creating i16 files. Either i15 or i16")
(options, args) = parser.parse_args()

act = options.action
Expand All @@ -208,7 +217,7 @@ def main():
parser.print_help()
print("\nYou must specify a file and wav_dir for create")
else:
create(options.file, options.wav_dir, options.normalize)
create(options.file, options.wav_dir, options.normalize, options.intrange)
elif act == "explode":
if(options.file is None or options.wav_dir is None):
parser.print_help()
Expand Down
11 changes: 7 additions & 4 deletions src/common/dsp/Wavetable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,14 @@ bool Wavetable::BuildWT(void *wdata, wt_header &wh, bool AppendSilence)
&((short *)wdata)[this->size * j], this->size);
if (this->flags & wtf_int16_is_16)
{
i16toi15_block(&this->TableI16WeakPointers[0][j][FIRoffsetI16],
&this->TableI16WeakPointers[0][j][FIRoffsetI16], this->size);
i162float_block(&this->TableI16WeakPointers[0][j][FIRoffsetI16],
this->TableF32WeakPointers[0][j], this->size);
}
else
{
i152float_block(&this->TableI16WeakPointers[0][j][FIRoffsetI16],
this->TableF32WeakPointers[0][j], this->size);
}
i152float_block(&this->TableI16WeakPointers[0][j][FIRoffsetI16],
this->TableF32WeakPointers[0][j], this->size);
}
}
else
Expand Down
32 changes: 28 additions & 4 deletions src/common/dsp/oscillators/WindowOscillator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ inline unsigned int BigMULr16(unsigned int a, unsigned int b)
return c >> 16u;
}

void WindowOscillator::ProcessWindowOscs(bool stereo, bool FM)
template <bool FM, bool Full16> void WindowOscillator::ProcessWindowOscs(bool stereo)
{
const unsigned int M0Mask = 0x07f8;
unsigned int SizeMask = (oscdata->wt.size << 16) - 1;
Expand Down Expand Up @@ -332,8 +332,9 @@ void WindowOscillator::ProcessWindowOscs(bool stereo, bool FM)
#endif

iWin[0] = (iWin[0] + iWin[1] + iWin[2] + iWin[3]) >> 13;
iWave[0] = (iWave[0] + iWave[1] + iWave[2] + iWave[3]) >> 13;
iWaveP1[0] = (iWaveP1[0] + iWaveP1[1] + iWaveP1[2] + iWaveP1[3]) >> 13;
iWave[0] = (iWave[0] + iWave[1] + iWave[2] + iWave[3]) >> (13 + (Full16 ? 1 : 0));
iWaveP1[0] =
(iWaveP1[0] + iWaveP1[1] + iWaveP1[2] + iWaveP1[3]) >> (13 + (Full16 ? 1 : 0));

iWave[0] = (int)((1.f - FTable) * iWave[0] + FTable * iWaveP1[0]);

Expand Down Expand Up @@ -414,7 +415,30 @@ void WindowOscillator::process_block(float pitch, float drift, bool stereo, bool
}
}

ProcessWindowOscs(stereo, FM);
bool is16 = oscdata->wt.flags & wtf_int16_is_16;

if (FM)
{
if (is16)
{
ProcessWindowOscs<true, true>(stereo);
}
else
{
ProcessWindowOscs<true, false>(stereo);
}
}
else
{
if (is16)
{
ProcessWindowOscs<false, true>(stereo);
}
else
{
ProcessWindowOscs<false, false>(stereo);
}
}

// int32 -> float conversion
__m128 scale = _mm_load1_ps(&OutAttenuation);
Expand Down
2 changes: 1 addition & 1 deletion src/common/dsp/oscillators/WindowOscillator.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class WindowOscillator : public Oscillator
void applyFilter();
template <bool is_init> void update_lagvals();

void ProcessWindowOscs(bool stereo, bool FM);
template <bool FM, bool Full16> void ProcessWindowOscs(bool stereo);
lag<double> FMdepth[MAX_UNISON];
lag<float> l_morph;

Expand Down
9 changes: 9 additions & 0 deletions src/common/dsp/vembertech/basic_dsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ inline void i152float_block(short *s, float *f, int n)
}
}

inline void i162float_block(short *s, float *f, int n)
{
const float scale = 1.f / (16384.f * 2);
for (int i = 0; i < n; i++)
{
f[i] = (float)s[i] * scale;
}
}

inline void i16toi15_block(short *s, short *o, int n)
{
for (int i = 0; i < n; i++)
Expand Down

0 comments on commit 2d4cde0

Please sign in to comment.