TX81Z algorithms


#23

you can also bitshift the phase of the sine oscillator and let it choose from tables with phase and amplitude offsets like:

int phs[4]={3,2,1,0};
int ofs[4]={1,1,-1,-1};
uint32_t phase;

phase+=freq;

int32_t r;
int32_t pos=phase>>30; //turns the phase into an integer from 0-3
int32_t p2=phase+(phs[pos]<<30); // adds the phase offset to the current phase
SINE2TINERP(p2,r)
r=r>>4;
r+=ofs[pos]<<27; // adds an amplitude offset to the sine so negative becomes positive and positive becomes negative.
outlet_out=r;


#24

This way, the CPU will be very low, but you will get lot of aliasing, which is not a bad thing if you want to replicate the TX81Z.


#26

Edit: Sorry, meant to reply to @SirSickSik.

I did some messing around with your code and was able to get 4/8 of the waveforms working with a similar method. I think the starting phase of these waveforms might be wrong but they look right on the scope. Here are my modifications:

int phs[4]  ={0,2,0,2};
int flp[4]  ={1,1,1,1}; //used to invert a part of the waveform
int mute[4] ={0,0,0,0}; //used to determine wether a particular part of the waveform should be set to 0

Phase += (freq + inlet_freq);
int32_t r;
int32_t pos=Phase>>30; //turns the phase into an integer from 0-3
int32_t p2 = Phase + (inlet_phase<<4) + (phs[pos]<<30);

SINE2TINTERP(p2,r);

r ^= flp[pos]?(1<<31):0;
wave_out= mute[pos]>0?0:(r>>4);
/*
Sine:

int phs[4]  ={0,0,0,0};
int mute[4] ={0,0,0,0};
int flp[4]  ={0,0,0,0};

Inverted Sine:

int phs[4]  ={0,2,0,2};
int mute[4] ={0,0,0,0};
int flp[4]  ={1,1,1,1};

Half Sine:

int phs[4]={3,2,1,3};
int on[4] ={0,1,1,0};
int flp[4]={0,0,0,0};

Inverted Half Sine:

int phs[4]={0,2,1,2};
int on[4] ={0,1,1,0};
int flp[4]={1,0,0,1};

*/

#27

I just wanted to show how this could be done in a way that could be made universal. I wrote this code from my head, not being totally sure whether it were the correct values. Good to see you got the point!

Anyways, to make the different waveforms, you can combine the tables in several ways:
-use one long table containing all the values of the different waveforms, but add an offset of 4 for each waveform:
int phs[8] ={0,0,0,0,0,2,0,2}; // put all the values into one table, make sure it's big enough to fit all of them
int mute[8] ={0,0,0,0,0,0,0,0};
int flp[8] ={0,0,0,0,1,1,1,1};
int wave=param_waveform<<2;
int32_t pos=(Phase>>30)+wave; //turns the phase into an integer from 0-3 and adds an offset for each waveform

you can also make a combined array (not sure what the correct technical term is for this), like
phs[8][4]=
{
{0,0,0,0},
{3,2,1,3},
{0,2,1,2},
etc...
}
the waveform selector would then select from the 8 different tables, each containing 4 values.

Anyways, these tables could of course be used to do all kinds of different things, eg. self-fm amounts:
-store the waveform output in the memory, so you can use it in the next cycle to do frequency modulation. Don't forget to use a hp-filter to remove DC-offsets, to prevent it from pitch-shifting away from it's base frequency.
-use different waveforms for output and self-fm, multiplying the phase of either one of them with an integer value creates harmonic overtones which can further increase the amount of spectra you can create. Also, giving the phase an offset can give totally different results, even though you're using the same waveform. Eg. in the case of a normal sine, no offset will generate a pulse-wave, but a 45 degrees offset will generate a saw-like waveform.
-perhaps a randomise function of the tables to find other interesting waveforms. Here, a hp-filter over the output is advisable, as some might create waveforms with an offset.
-use another table to multiply the phase to create seperate harmonic overtones in the 4 parts of the phase.
-another thing that might be interesting is to use the actual phase-offset, amplitude and flip values (eg. (1<<30)=45 degrees) and morph between the table values to morph between waveforms.

int a,b;
int32_t mix,value;

a=(uint64_t)param_morph*8>>27;//turns the parameter value in the range of 0-7
b=(a+1)%8;//offset of 1 to select the value of the next waveform
mix=((uint32_t)param_morph*8<>1;//gives the remainder without using the bits used by the wave-selection (a/b) and turns it into a range of 0-(1<<31)
value=phs[a][0]+(___SMMUL(phs[b][0]-phs[a][0],mix)<<1);//mixes between wave selection by a and selection by b.

ps I normally use a simple lp/hp filter calculation for dc-offset removal:

hp+=wave-hp>>9; (simple 6dB lowpass function around 30hz if I'm right, not sure though, but works well enough for self-fm, sometimes I even use 8,7 or 6, which will increase the frequency of the hp filter)
wave-=hp; (subtract lowpass from original to create hp-filtered wave)


#28

I made a quick randomisable tone generator based on this, using some of the ideas I posted. Did show me where I made a mistake in my previous code I posted. I calculated the phase offset without taking into consideration that the phase it was added to, was itself of course still giving an extra offset all the time. Fixed this by doing:
p2=phase&((1<<30)-1)+phs[pos];
This way you can enter the phase positions as where the sine should start instead of recalculating with the current phase offset
Also tried to soften the waveform a bit by adding the waveform amplitude difference at moments of table-changes to a value that constantly tries to slowly return to 0.

something like this.axp (6.3 KB)