How do you go about sampling wavetables?

cytospur
 KVRian
 1323 posts since 26 Jun, 2002 from London, UK
Re: How do you go about sampling wavetables?
It took me just a few minutes to reset the phases in the Legacy wavetable, which contains 60 waveforms. Just to give you an idea of how quick it is.
Wavetables for DUNE2/3, Blofeld, IL Harmor, Hive and Serum etc: http://charlesdickens.neocities.org/
£10 for lifetime updates including wavetable editor for Windows.
Music: https://soundcloud.com/markholt
£10 for lifetime updates including wavetable editor for Windows.
Music: https://soundcloud.com/markholt

chk071
 KVRAF
 21584 posts since 11 Apr, 2010 from Germany
Re: How do you go about sampling wavetables?
I tried to do what you said, but, it seems like it automatically normalizes the waveform in the process, which, of course, i don't want, as i already normalized the whole wavetable. Also, i'm kind of confused about the display or partials. What is actually happening, when i sweep all partials' phase to zero?

aciddose
 KVRAF
 12277 posts since 7 Dec, 2004
Re: How do you go about sampling wavetables?
You definitely don't want to set all partials to zero phase.
Every N sample waveform can be represented by N/2 (amplitude, phase) pairs.
The first "0" partial is DC.
If you have a cycle of 1024 samples the highest harmonic is then harmonic #511 at 511 times the frequency.
If you want to look at additive synthesis based upon formulae you should easily find additive synthesizers that let you both specify a formula for amplitude and phase as well as tweak the individual (amp, ph) pair for each partial.
The basic "geometric" waveforms are almost all "phase = 0". 0 is equal to 1 if we're using percentage rather than degrees or radians and you'll very often see a preference for "phase = 1" rather than "phase = 0", but that's all up to personal preference.
Some symbols used:
= is "equivalence"
/ is division
* is multiplication
^ is raising to a power
I'll use functional notation to express other concepts:
skip(N) means the output = 1 except for every N which is = 0.
In other words skip(2) for example would zero all even harmonics.
rotate(N) means for each N, rotate the phase by 1/N.
In other words rotate(4) would give phase = 0, 1/4, 2/4, 3/4, 0, 1/4, ...
Assuming all phases are equal, the basic waveforms are:
sine = 1, 0, first only
impulse = 1, 0, all
ramp = 1/N, 0, 1
square = 1/N, 0, skip(2)
So looking at square and considering the fact we skip even harmonics with skip(2), don't you wonder what might happen if you use skip(3) or skip(...) instead?
staircase3 = 1/N, 0, skip(3)
It turns out "square" is just a staircase waveform with two steps!
staircase4 = 1/N, 0, skip(4)
triangle = 1/N^2, rotate(4), skip(2)
Again... we must wonder what rotate(N) does. skip(N) is boring since we know the relationship between staircase2 and triangle is simply that it's been integrated, so sharp edges are smoothed out. Therefore triangle with skip(3) is staircase3 with straight lines and so forth... almost.
It fact it doesn't work out that way because the phase relationship doesn't line up with rotate(N) anymore. As you work with more complex shapes you'll find things become less intuitive (there are multiplications and higher order between things) and it can help to draw the geometric shape directly then try to create the numbers you get from a fourier transform.
One interesting thing about this though is if you observe the difference in the peak amplitude of the triangle you'll see it's way beyond 1.0 or "0 dB". So by modifying the phase we can get something that sounds exactly like a triangle with a lower peak amplitude.
When we don't bother to rotate the phase for every oddodd harmonic of the triangle we get this:
parabola = 1/N^2, 0, skip(2)
So that's why mucking with phases is a bad idea. You'll change the peak and overall waveform significantly when you do that. You might have a geometric shape based on straight lines and you'll end up with something like this instead:
Every N sample waveform can be represented by N/2 (amplitude, phase) pairs.
The first "0" partial is DC.
If you have a cycle of 1024 samples the highest harmonic is then harmonic #511 at 511 times the frequency.
If you want to look at additive synthesis based upon formulae you should easily find additive synthesizers that let you both specify a formula for amplitude and phase as well as tweak the individual (amp, ph) pair for each partial.
The basic "geometric" waveforms are almost all "phase = 0". 0 is equal to 1 if we're using percentage rather than degrees or radians and you'll very often see a preference for "phase = 1" rather than "phase = 0", but that's all up to personal preference.
Some symbols used:
= is "equivalence"
/ is division
* is multiplication
^ is raising to a power
I'll use functional notation to express other concepts:
skip(N) means the output = 1 except for every N which is = 0.
In other words skip(2) for example would zero all even harmonics.
rotate(N) means for each N, rotate the phase by 1/N.
In other words rotate(4) would give phase = 0, 1/4, 2/4, 3/4, 0, 1/4, ...
Assuming all phases are equal, the basic waveforms are:
sine = 1, 0, first only
impulse = 1, 0, all
ramp = 1/N, 0, 1
square = 1/N, 0, skip(2)
So looking at square and considering the fact we skip even harmonics with skip(2), don't you wonder what might happen if you use skip(3) or skip(...) instead?
staircase3 = 1/N, 0, skip(3)
It turns out "square" is just a staircase waveform with two steps!
staircase4 = 1/N, 0, skip(4)
triangle = 1/N^2, rotate(4), skip(2)
Again... we must wonder what rotate(N) does. skip(N) is boring since we know the relationship between staircase2 and triangle is simply that it's been integrated, so sharp edges are smoothed out. Therefore triangle with skip(3) is staircase3 with straight lines and so forth... almost.
It fact it doesn't work out that way because the phase relationship doesn't line up with rotate(N) anymore. As you work with more complex shapes you'll find things become less intuitive (there are multiplications and higher order between things) and it can help to draw the geometric shape directly then try to create the numbers you get from a fourier transform.
One interesting thing about this though is if you observe the difference in the peak amplitude of the triangle you'll see it's way beyond 1.0 or "0 dB". So by modifying the phase we can get something that sounds exactly like a triangle with a lower peak amplitude.
When we don't bother to rotate the phase for every oddodd harmonic of the triangle we get this:
parabola = 1/N^2, 0, skip(2)
So that's why mucking with phases is a bad idea. You'll change the peak and overall waveform significantly when you do that. You might have a geometric shape based on straight lines and you'll end up with something like this instead:
Free plugins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.

chk071
 KVRAF
 21584 posts since 11 Apr, 2010 from Germany
Re: How do you go about sampling wavetables?
TBH, i'm close to give up. Total pain in the butt to get the single waves phase aligned correctly. And, even the slightest difference in phase will end in a bad result, when sweeping through the wavetable. Unfortunately, Wavelab also doesn't detect the zero crossings reliably, when the phase of the waveform starts with a negative value, and, when you edit it manually, a few samples can already mess up the morphing.
Guess this "dirty" way of doing it (resampling) is really not very worthwhile.
Guess this "dirty" way of doing it (resampling) is really not very worthwhile.

Shabdahbriah
 KVRAF
 4920 posts since 19 Jun, 2008 from Seattle
Re: How do you go about sampling wavetables?
Very interesting, Thank you.
Perception is the ultimate "reality" ~ but not, the ultimate Truth.

alienmachine
 KVRist
 347 posts since 13 Sep, 2004
Re: How do you go about sampling wavetables?
I just read this topic while researching information about wavetables. I was trying to do the same for the M1 ROMs by analyzing a memory dump file with Windows debugging tools, but haven't had the time to continue. The D50 wave ROM was really easy: it is a resource built into a DLL as 32bit float raw waves.aciddose wrote: ↑Tue Jan 01, 2019 9:42 amI just dump the process memory. You'll likely find the PCM format samples whether in raw format (like .wav?) or floating point or whatever else along with names, loop points, tuning, key maps and so on.
This is slightly advanced reversing but it is "still in diapers" level, so anyone with enough dedication can learn to do it. Try finding a "heap walker" tool that allows you to browse the heap allocations of a process and dump those blocks into files. Also it would help if you write your own "host" as an extremely barebones shell application so you have essentially a standalone plugin instance allocated with a minimum number of system libraries mapped which greatly simplifies things.
I'm extremely picky about these things though.
For example years ago we talked about D50 and M1 ROMs... since then I've dumped these successfully and reverse engineered a majority of their code/structures. Recently I've been working on an alpha juno ROM to allow me to make modifications to disable the "all notes off" on last noteoff and remap the pedals. I'm 80% of the way there, the hard part has actually been finding a reliable source for rewritable EPROMs to use while debugging so I may need to create an adapter using a modern SMD eprom to fit in the firmware ROM socket.
https://soundcloud.com/aciddose1/jim1
https://soundcloud.com/aciddose1/stringitize
Unfortunately what I've personally found after achieving this? The samples are god awful garbage and it wasn't anywhere near worth the effort.
As far as "alpha juno as a controller"... an interesting passtime but realistically way more efficient to just use a real controller. The alpha juno board sucks.
A heap walker is definitely something I would try, haven't thought about it

aciddose
 KVRAF
 12277 posts since 7 Dec, 2004
Re: How do you go about sampling wavetables?
The format of the plugin is horrid, so I would recommend you reverse the M1 ROMs themselves instead. There are numerous softwarespecific optimizations used in the plugin and the data does NOT match the original data structures in the M1 hardware ROMs.
Free plugins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.

alienmachine
 KVRist
 347 posts since 13 Sep, 2004
Re: How do you go about sampling wavetables?
Thank you for the info. Actually, that was my first choice, I just haven’t found the actual ROM files anywhere. I did found the Wavestation’s though.

alienmachine
 KVRist
 347 posts since 13 Sep, 2004
Re: How do you go about sampling wavetables?
Hi there,
I actually found the M1 data. Nice!
I'm writing a little Python program to decode the data as they are stored in LSB & MSB format in different masked ICs.

aciddose
 KVRAF
 12277 posts since 7 Dec, 2004
Re: How do you go about sampling wavetables?
There are a lot of weird pointer tables used. At first I thought since the processor was "roughly intel 286 compatible" it should be possible to disassemble the binary directly and step through the code to figure how to handle the data.
Unfortunately these old NEC chips use a nasty feature of the older processors called segment wrapping. When you compute a pointer you have a segment+offset pair... but the two values aren't entirely distinct, they overlap quite a bit. So since there are multiple overlapping pages and a limited total number of bits (21 was it?) the full address computed might end up wrapping in a difficult to predict way.
https://en.wikipedia.org/wiki/X86_memory_segmentation
This isn't terribly complicated to be honest... but IDA (the disassembler) does NOT support it. So any pointers computed from "by hand" segment/offset won't be handled correctly, and the disassembler won't be able to fully disassemble or identify what type or address of memory is being accessed. So you're forced to manually disassemble or write your own disassembler which is a nightmarish amount of work, either way.
On top of that the M1 code not only uses segment wrapped addresses in the code itself, the data structures contain similarly wrapped pointer data to other substructures in a complicated hierarchy of structures.
I got as far as fully decoding all the samples correctly, but at that point I lost most of my interest and never fully identified all the data structures or members. I mostly reversed the binary but IDA actually fights against you if it's allowed to automatically process anything since it doesn't understand page wrapping is limited to N bits on that specific processor (the generic 386 or 286 is used, there is no direct NEC chip support.) Due to that there is no real point to getting the code disassembled, since the advantage is automatic identification of data blocks... and without that you're manually trying to work everything out anyway.
Apparently it is possible to get it to work partially with a full version of IDA but... well, decoding the M1 data isn't worth $10,000 to me. The authors of the official korg software might have access to the original source code instead, which would be way more easy to work with.
Unfortunately these old NEC chips use a nasty feature of the older processors called segment wrapping. When you compute a pointer you have a segment+offset pair... but the two values aren't entirely distinct, they overlap quite a bit. So since there are multiple overlapping pages and a limited total number of bits (21 was it?) the full address computed might end up wrapping in a difficult to predict way.
https://en.wikipedia.org/wiki/X86_memory_segmentation
This isn't terribly complicated to be honest... but IDA (the disassembler) does NOT support it. So any pointers computed from "by hand" segment/offset won't be handled correctly, and the disassembler won't be able to fully disassemble or identify what type or address of memory is being accessed. So you're forced to manually disassemble or write your own disassembler which is a nightmarish amount of work, either way.
On top of that the M1 code not only uses segment wrapped addresses in the code itself, the data structures contain similarly wrapped pointer data to other substructures in a complicated hierarchy of structures.
I got as far as fully decoding all the samples correctly, but at that point I lost most of my interest and never fully identified all the data structures or members. I mostly reversed the binary but IDA actually fights against you if it's allowed to automatically process anything since it doesn't understand page wrapping is limited to N bits on that specific processor (the generic 386 or 286 is used, there is no direct NEC chip support.) Due to that there is no real point to getting the code disassembled, since the advantage is automatic identification of data blocks... and without that you're manually trying to work everything out anyway.
Apparently it is possible to get it to work partially with a full version of IDA but... well, decoding the M1 data isn't worth $10,000 to me. The authors of the official korg software might have access to the original source code instead, which would be way more easy to work with.
Free plugins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.