diff --git a/Part #7 - Mappers & Basic Sounds/olc2A03.cpp b/Part #7 - Mappers & Basic Sounds/olc2A03.cpp index 9953fe5..7e6b6d8 100644 --- a/Part #7 - Mappers & Basic Sounds/olc2A03.cpp +++ b/Part #7 - Mappers & Basic Sounds/olc2A03.cpp @@ -145,6 +145,19 @@ void olc2A03::cpuWrite(uint16_t addr, uint8_t data) break; case 0x4008: + triangle_lc.counter = (data & 0x7F); + triangle_halt = (data & 0x80); + break; + + case 0x400A: + triangle_seq.reload = (triangle_seq.reload & 0xFF00) | data; + break; + + case 0x400B: + triangle_seq.reload = (uint16_t)((data & 0x07)) << 8 | (triangle_seq.reload & 0x00FF); + triangle_seq.timer = triangle_seq.reload; + // TODO: length counter + linear counter + //triangle_lc.additional_counter = (data & 0xF8) >> 3; break; case 0x400C: @@ -179,6 +192,7 @@ void olc2A03::cpuWrite(uint16_t addr, uint8_t data) pulse1_enable = data & 0x01; pulse2_enable = data & 0x02; noise_enable = data & 0x04; + triangle_enable = data & 0x08; break; case 0x400F: @@ -264,6 +278,7 @@ void olc2A03::clock() pulse1_lc.clock(pulse1_enable, pulse1_halt); pulse2_lc.clock(pulse2_enable, pulse2_halt); noise_lc.clock(noise_enable, noise_halt); + triangle_lc.clock(triangle_enable, triangle_halt); pulse1_sweep.clock(pulse1_seq.reload, 0); pulse2_sweep.clock(pulse2_seq.reload, 1); } @@ -326,9 +341,33 @@ void olc2A03::clock() noise_output = (double)noise_seq.output * ((double)(noise_env.output-1) / 16.0); } + { + // Update triangle Channel ================================ + triangle_seq.clock(triangle_enable, [](uint32_t& s) + { + // Shift right by 1 bit, wrapping around + s = ((s & 0x0001) << 7) | ((s & 0x00FE) >> 1); + }); + + } + // else + { + triangle_osc.frequency = 1789773.0 / (32.0 * (double)(triangle_seq.reload + 1)); + triangle_osc.amplitude = (double)1.0; + triangle_sample = triangle_osc.sample(dGlobalTime); + + if (triangle_lc.counter > 0 && triangle_seq.timer >= 8) + triangle_output += (triangle_sample - triangle_output) * 0.5; + else + triangle_output = 0; + } + + + if (!pulse1_enable) pulse1_output = 0; if (!pulse2_enable) pulse2_output = 0; if (!noise_enable) noise_output = 0; + if (!triangle_enable) triangle_output = 0; } @@ -339,6 +378,7 @@ void olc2A03::clock() pulse1_visual = (pulse1_enable && pulse1_env.output > 1 && !pulse1_sweep.mute) ? pulse1_seq.reload : 2047; pulse2_visual = (pulse2_enable && pulse2_env.output > 1 && !pulse2_sweep.mute) ? pulse2_seq.reload : 2047; noise_visual = (noise_enable && noise_env.output > 1) ? noise_seq.reload : 2047; + triangle_visual = (triangle_enable) ? triangle_seq.reload : 2047; clock_counter++; } @@ -352,9 +392,12 @@ double olc2A03::GetOutputSample() } else { + //return + // ((1.0 * triangle_output) - 0.5) * 0.2; return ((1.0 * pulse1_output) - 0.8) * 0.1 + ((1.0 * pulse2_output) - 0.8) * 0.1 + - ((2.0 * (noise_output - 0.5))) * 0.1; + ((2.0 * (noise_output - 0.5))) * 0.1 + + ((1.0 * triangle_output) - 0.8) * 0.1; } } diff --git a/Part #7 - Mappers & Basic Sounds/olc2A03.h b/Part #7 - Mappers & Basic Sounds/olc2A03.h index 63995f3..2e568a0 100644 --- a/Part #7 - Mappers & Basic Sounds/olc2A03.h +++ b/Part #7 - Mappers & Basic Sounds/olc2A03.h @@ -238,6 +238,32 @@ class olc2A03 } }; + struct osctriangle + { + double frequency = 0; + double amplitude = 1; + double pi = 3.14159; + //double harmonics = 20; + + double sample(double t) + { + double a = 0; + double b = 0; + + auto approxsin = [](float t) + { + float j = t * 0.15915; + j = j - (int)j; + return 20.785 * j * (j - 0.5) * (j - 1.0f); + }; + + a = approxsin(2 * pi * frequency * t); + b = approxsin(2 * pi * frequency * t * 3) / 9 - approxsin(2 * pi * frequency * t * 5) / 25 + approxsin(2 * pi * frequency * t * 7) / 49; + + return (2.0 * amplitude / pi) * (a - b); + } + }; + struct sweeper { bool enabled = false; @@ -327,6 +353,14 @@ class olc2A03 double noise_sample = 0; double noise_output = 0; + // Triangle Wave Channel + bool triangle_enable = false; + bool triangle_halt = false; + double triangle_sample = 0.0; + double triangle_output = 0.0; + sequencer triangle_seq; + osctriangle triangle_osc; + lengthcounter triangle_lc; public: uint16_t pulse1_visual = 0;