Using a 2A03 by itself + programming
Moderator: Moderators
The problem is that it's not only a music engine; it's made to interface with CV signals on a modular synthesizer, in addition to reading rotary encoders. For example, synth modules use a standard pitch control format of +1V = +1 octave. So I need to sample an analog voltage and scale the digital result to be base 2 logarithmic before it can set the pitch of an NES channel. I would not know where to begin doing that math in assembly, but I can write it out quickly in CDwedit wrote:If you're only making a music engine, I'd bet a 6502 C compiler would be fast enough.
Sorry I have been quiet for a while. I put the NES project on a little break while I worked on an Atari synth module. A lot of the microcontroller code will be the same for both. The Atari synth is almost done except for a single algorithm speed problem.
Speaking of which, is there a fast method to calculate 2 to a rational power? The C pow(2, x) compiled on my micro takes almost a full millisecond to execute! I wrote my own function that's accurate to 0.06% using a mix of math and small lookup tables, but it still takes around 200 micro seconds. I hope asking about such is not going too far off topic on this forum.
Or 1/1200 V per cent of pitch.skrasms wrote:The problem is that it's not only a music engine; it's made to interface with CV signals on a modular synthesizer, in addition to reading rotary encoders. For example, synth modules use a standard pitch control format of +1V = +1 octave.
Lookup tables. Lots of lookup tables.So I need to sample an analog voltage and scale the digital result to be base 2 logarithmic before it can set the pitch of an NES channel. I would not know where to begin doing that math in assembly
I wanted to make a lookup table that covered all 12 bits, but I cannot really fit more than a couple hundred values into the micro's RAM. Right now my code is based on table lookups and somewhat simple math. It takes the exponent and breaks it into individual digits, then uses lookup tables to get 2 to that digit.tepples wrote:Lookup tables. Lots of lookup tables.skrasms wrote:So I need to sample an analog voltage and scale the digital result to be base 2 logarithmic before it can set the pitch of an NES channel. I would not know where to begin doing that math in assembly
For example, 2^3.124
= (2^3)*(2^0.1)*(2^0.02)*(2^0.004)
= two1[3] * two01[1] * two001[2] * two0001[4]
Code: Select all
double two1[] = {1.000000000000000, 2.000000000000000, 4.000000000000000, 8.000000000000000, 16.000000000000000, 32.000000000000000, 64.000000000000000, 128.000000000000000, 256.000000000000000, 512.000000000000000};
double two01[] = {1.000000000000000, 1.071773462536293, 1.148698354997035, 1.231144413344916, 1.319507910772894, 1.414213562373095, 1.515716566510398, 1.624504792712471, 1.741101126592248, 1.866065983073615};
double two001[] = {1.000000000000000, 1.006955550056719, 1.013959479790029, 1.021012125707193, 1.028113826656067, 1.035264923841378, 1.042465760841121, 1.049716683623067, 1.057018040561380, 1.064370182453360};
double two0001[] = {1.000000000000000, 1.000693387462581, 1.001387255711335, 1.002081605079633, 1.002776435901078, 1.003471748509503, 1.004167543238973, 1.004863820423785, 1.005560580398468, 1.006257823497782};
double two00001[] = {1.000000000000000, 1.000069317120377, 1.000138639045616, 1.000207965776052, 1.000277297312018, 1.000346633653845, 1.000415974801869, 1.000485320756421, 1.000554671517834, 1.000624027086444};
double mypow(double val);
double mypow(double val)
{
unsigned dig[5];
double old = val;
if(val<0) val = -val;
dig[0] = (unsigned)val;
dig[1] = ((unsigned)(val*10))%10;
dig[2] = ((unsigned)(val*100))%10;
dig[3] = ((unsigned)(val*1000))%10;
dig[4] = ((unsigned)(val*10000))%10;
if(old<0) return(1 / two1[dig[0]] / two01[dig[1]] / two001[dig[2]] / two0001[dig[3]] / two00001[dig[4]]);
else return(two1[dig[0]] * two01[dig[1]] * two001[dig[2]] * two0001[dig[3]] * two00001[dig[4]]);
}
I noticed that your code extracts the decimal digits. Try extracting hexadecimal digits instead; division by 16 is usually much faster than division by 10 on cheap processors. In addition, double is slower than a fixed-point data type unless your processor has specific circuitry (called an FPU) for handling doubles.skrasms wrote:I wanted to make a lookup table that covered all 12 bits, but I cannot really fit more than a couple hundred values into the micro's RAM. Right now my code is based on table lookups and somewhat simple math. It takes the exponent and breaks it into individual digits, then uses lookup tables to get 2 to that digit.
I had to take a break from this project because of school and graduation, but I'm back on it now
Now that I can write registers, I am able to get sound out from the Triangle, Noise, and DMC channels. I tried this order for using the triangle channel:
Write 0x7F to $4008
Write 0x11 to $400A
Write 0x30 to $400B
Any time I write to $400A the triangle channel goes silent. Is that supposed to happen? Writing to $400B brings it back at the updated frequency.
In the same way, after I write to $400E the noise channel goes silent. It comes back when I write any arbitrary data to $400F.
So this process works:
Write 0x1F to 0x400C
Write 0x88 to 0x400E
Write 0xXX (any value) to 0x400F
But this process does not:
Write 0x1F to 0x400C
Write 0x88 to 0x400E
Is that normal behavior?
Now that I can write registers, I am able to get sound out from the Triangle, Noise, and DMC channels. I tried this order for using the triangle channel:
Write 0x7F to $4008
Write 0x11 to $400A
Write 0x30 to $400B
Any time I write to $400A the triangle channel goes silent. Is that supposed to happen? Writing to $400B brings it back at the updated frequency.
In the same way, after I write to $400E the noise channel goes silent. It comes back when I write any arbitrary data to $400F.
So this process works:
Write 0x1F to 0x400C
Write 0x88 to 0x400E
Write 0xXX (any value) to 0x400F
But this process does not:
Write 0x1F to 0x400C
Write 0x88 to 0x400E
Is that normal behavior?