/*
Risc os Digital Signal Processor
(C) 2017-2019 A.V.Bartram

THIS SOFTWARE IS PROVIDED  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL A.V.Bartram BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL
,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO
),PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS
;OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/

#include <ctype.h>
#include "kernel.h"
#include "synth.h"

//      Veneer based on studying the DDE guide &
//      http://www.riscos.com/support/developers/c/cpasm.html

// Placed inside s.dspif (DSP interface)

DWORD buffer_fill(void* param, signed short* buffer_base, signed short* buffer_end, DWORD flags)
{
    int clearBuffer = 0;
    int j;
    BUFFER_TYPE32 channelBufferL;
    BUFFER_TYPE32 channelBufferR;
    RISC_SYNTH *synth_channel = (RISC_SYNTH*)param;
    int watermark = 0;
    int fxwatermark = 0;
    size_t lengthbuffer = (size_t)(buffer_end - buffer_base) / 2;

    channelBufferL.m_data = synth_channel->m_fillBufferLeft;
    channelBufferR.m_data = synth_channel->m_fillBufferRight;
    // First, check if we need to clear the buffer or add to it
    if (flags & 1)
        clearBuffer =1;

    if (lengthbuffer > 44100)
    {
        if (!clearBuffer)
        {
            signed short *ptr = buffer_base;
            while (ptr <= (buffer_end-2))
            {
                ptr[0] = 0;
                ptr++;
                ptr[1] = 0;
                ptr++;
            }
        }
    }
    else
    {
        signed short *ptr = buffer_base;
        channelBufferL.m_size = lengthbuffer;
        channelBufferL.m_dataLength = 0;
        channelBufferR.m_size = lengthbuffer;
        channelBufferR.m_dataLength = 0;
        // For each channel 0 to 15
        for (j = 0; j < MAX_POLY; ++j)
        {
            BUFFER_TYPE32 *bufferL = &channelBufferL;
            BUFFER_TYPE32 *bufferR = &channelBufferR;

            BUFFER_TYPE *xorchannel = NULL;
            BUFFER_TYPE xorimpl;
            signed short *xornext =  ((RISC_SYNTH*)param)->m_lastChannel[(j&1)];
            SYNTH_CHANNEL *channel = ((RISC_SYNTH*)param)->m_channel+j;

            unsigned int length = 0;
            unsigned int i;
            int          signal = 0;
            DCO          dco;
            LPF          lpf;

            int          res = 0;
            int          signali = 0;

            int          resUp = 0;
            int          amplifier = 0;
            int          wave = 0;
            int          tone = 0;
            int          pulse_width = 0;

            if (channel->m_adsr.m_stage >= channel->m_adsr.m_endState)
            {
              // If the RDSP channel queue contains data - pick up the
              // next note if the current channel is idle i.e.
              // ADSR is always used even for simple tones - and endstate
              // identifies that the channel has reached then end.

              // Channel is empty - check if channel queue contains notes
              RISC_SYNTH *synth = (RISC_SYNTH*)param;
              if (synth->m_queue[j].m_reader != synth->m_queue[j].m_writer)
              {
                int r = synth->m_queue[j].m_reader+1;
                int osclkp = synth->m_channel[j].m_dco.m_osc_lookup;
                if (r == MAX_QUEUE_BUFFER)
                {
                  r = 0;
                }

                memcpy(&(synth->m_channel[j]),
                       &(synth->m_queue[j].m_ringBuffer[r]),
                       sizeof(SYNTH_CHANNEL));
                synth->m_queue[j].m_reader = r;
                // prserve osc state
                if (synth->m_channel[j].m_wave != 0)
                {
                  synth->m_channel[j].m_dco.m_osc_lookup = osclkp;
                }

              }
            }
            // Local variables may be faster than memory referenced
            // So copy channel state to temporary local variables so
            // they can be worked upon to generate a signal from RDSP
            // i.e. a sound on the current channel.
            lpf.pole1 = channel->m_lpf.pole1;
            lpf.pole2 = channel->m_lpf.pole2;
            lpf.cutoff = channel->m_lpf.cutoff;
            lpf.resonance = channel->m_lpf.resonance;
            dco.m_osc_lookup = channel->m_dco.m_osc_lookup;
            dco.m_sample_lookup_msw = channel->m_dco.m_sample_lookup_msw;
            dco.m_sample = channel->m_dco.m_sample;
            dco.m_sample.m_loop = channel->m_dco.m_sample.m_loop;
            dco.m_sample.m_loopBack = channel->m_dco.m_sample.m_loopBack;
            amplifier = channel->m_amp;
            wave = channel->m_wave;
            tone = channel->m_tone;
            pulse_width = channel->m_pulse_width;
            // Should only compute if cutoff changes as div is expensive
            // resUp is used by the low pass filter to implement the
            // Resonance or Q : this is implemented using feedback
            // which must be exponentially higher for lower frequencies
            // so that the feedback does not die away too quickly.
            resUp = 1 << ((256-lpf.cutoff)>>6);

            // This implements the XOR mixing between channels which
            // creates science fiction style effects. The SID chip and
            // MS-20 both used this as a crude ring modulator effect.

            // This code finds the channel to use as the XOR mixing channel.
            if ((channel->m_mode & CHANNEL_MODE_XOR) && (j>0))
            {
                int x = j&1;
                if (x == 0)
                  x = 1;
                else
                  x = 0;

                xorchannel = &xorimpl;
                xorimpl.m_data =((RISC_SYNTH*)param)->m_lastChannel[x];
            }

            // This loop generates the signal waveform to be mixed into the
            // callers buffer.
            if (channel->m_adsr.m_stage < channel->m_adsr.m_endState)
            for (i = 0; (i < lengthbuffer); ++i)
            {
                {
                    unsigned int osc_control = dco.m_osc_lookup >> 14 ; // Currently fractions are in 1/16384ths..

                    // All oscillators are by default slightly detuned to create
                    // simple phase effect.
                    if ((channel->m_mode & CHANNEL_MODE_SYNC) == 0)
                    {
                        dco.m_osc_lookup += (j << 4);
                    }

                    signal = 0; // signal change start
                    if (wave == 0)
                    {
                        if (dco.m_sample.m_data != NULL)
                        {
                            int playposition = (dco.m_sample_lookup_msw << 16) +
                            (dco.m_osc_lookup >> 14);
                            dco.m_osc_lookup = dco.m_osc_lookup + synth_channel
->sampleFreqTable[tone];
                            if (dco.m_osc_lookup > 1073741824)
                            {
                                dco.m_osc_lookup -= 1073741824;
                                dco.m_sample_lookup_msw ++;
                            }
                            // Sample loop
                            if (dco.m_sample.m_loop)
                            {
                                if (playposition >= dco.m_sample.m_loop)
                                {
                                    dco.m_sample_lookup_msw = dco.m_sample.m_loopBack >> 16;
                                    dco.m_osc_lookup =
                                       (dco.m_sample.m_loopBack & 0xffff) << 14;
                                }
                            }

                            if (playposition >= dco.m_sample.m_dataLength)
                            {
                                dco.m_osc_lookup = 0;

                                channel->m_adsr.m_stage = channel->m_adsr.m_endState;
                                break;
                            }

                            signal = dco.m_sample.m_data[playposition];

                        }
                    }
                    else
                    {
                        dco.m_osc_lookup = dco.m_osc_lookup + synth_channel->tonetable[tone];

                        if (dco.m_osc_lookup >= OSC_SIZE)
                        dco.m_osc_lookup -= OSC_SIZE; // Modulus wil be expensive unless it is base 2

                        // pulse / square
                        if (wave & 0x1f)
                        {
                            signal = osc_control < pulse_width ? SWITCH_TOP_AMP : SWITCH_BASE_AMP;
                        }
                        // saw wave
                        if (wave & WAVEFORM_SAW)
                        {
                            if ((wave & 0xdf)&&signal!=0)
                            signal &= osc_control - HALF_SAMPLE_RATE;
                            else
                            signal = osc_control - HALF_SAMPLE_RATE;
                        }

                        // triangle wave
                        if (wave & WAVEFORM_TRIANGLE)
                        {
                            if ((wave & 0xbf)&&signal!=0)
                            {
                                int s = osc_control < HALF_SAMPLE_RATE ? osc_control : SAMPLE_RATE - osc_control;
                                s -= QUARTER_SAMPLE_RATE;
                                signal &= s;
                            }
                            else
                            {
                                signal = osc_control < HALF_SAMPLE_RATE ? osc_control : SAMPLE_RATE - osc_control;
                                signal -= QUARTER_SAMPLE_RATE;
                                signal = signal * 2; // triangle is quieter - normal raise- to +11k.
                            }
                        }
                        // modulatable noise (logarithmic)
                        if (wave & WAVEFORM_NOISE)
                        {
                            // allow LCG prng to repeat last value mix into the signal
                            // 41860090 == run every time
                            //   218267 == lowest frequency
                            channel->m_noise_throttle += synth_channel->tonetable[tone];
                            if (channel->m_noise_throttle >= synth_channel->tonetable[MAX_TONE-1])
                            {
                                channel->m_noise_throttle -= synth_channel->tonetable[MAX_TONE-1];
                                // Trivial linear congruential generator.
                                // Using the sample constants as Borland C for now
                                channel->m_prng = (22695477 * channel->m_prng) + 1;
                                // prng is a 2^32 number, so as usual Modulus is automatic.
                            }


                            if ((wave & 0x7f)&&signal!=0)
                            {
                                unsigned int tmp = channel->m_prng >> 31;

                                if (tmp & 1)
                                {
                                    signal &= SWITCH_BASE_AMP;
                                }
                                else
                                {
                                    signal &= SWITCH_TOP_AMP;
                                }
                            }
                            else
                            {
                                unsigned int tmp = channel->m_prng >> 31;

                                if (tmp & 1)
                                {
                                    signal = SWITCH_BASE_AMP;
                                }
                                else
                                {
                                    signal = SWITCH_TOP_AMP;
                                }
                            }
                        }
                    }

                    // Channel can be ring-modulated (via simple XOR) with adjacent channel i.e. 1 with channel 2, 3 with 4, 5 with 6 and 7 with 8
                    if (xorchannel)
                    {
                        signal = signal ^ xorchannel->m_data[i];
                    }
                    if (signal < 0)
                    {
                        signal = signal * -1;
                        signal = (signal * amplifier) >> 8; // Amplifier is 0 to 256
                        signal = signal * -1;
                    }
                    else
                    {
                        signal = (signal * amplifier) >> 8; // Amplifier is 0 to 256
                    }
                }
                //

                // Envelopes - pitch, amp or filter
                channel->centisecond++;
                if (channel->centisecond == CENTISECOND)
                {
                    channel->centisecond = 0;
                    // I now have 2 envelopes that can modulate more than 1 source
                    // The 3 stage env can loop and modulate any value including amplitude.

                    if (channel->m_adr.m_stage < channel->m_adr.m_endState)
                    {
                        int cont = 1;

                        // ADR supports a speed parameter
                        if (channel->m_adr.m_counterSpeed > 1)
                        {
                            channel->m_adr.m_speedCounter++;
                            if (channel->m_adr.m_speedCounter <= channel->m_adr.m_counterSpeed)
                            cont = 0;
                            else
                            channel->m_adr.m_speedCounter = 0;
                        }

                        if (cont)
                        {
                            channel->m_adr.m_stageCounter++;
                            if (channel->m_adr.m_stageCounter >= channel->m_adr.m_numADSR[channel->m_adr.m_stage])
                            {
                                channel->m_adr.m_stageCounter = 0;
                                channel->m_adr.m_stage++;
                                if (channel->m_adr.m_stage == channel->m_adr.m_endState)
                                {
                                    if (channel->m_adr.m_flags & ASR_FLAG_LOOP)
                                    {
                                        channel->m_adr.m_stage = 0;
                                    }
                                    else
                                    {
                                        cont = 0;
                                    }
                                }
                            }
                        }

                        if (cont)
                        {
                            if (channel->m_adr.m_flags & ASR_FLAG_PITCH)
                            {
                                tone = (tone + channel->m_adr.m_stepADSR[channel->m_adr.m_stage]);
                                if (tone >= 364)
                                tone -= 364;
                                if (tone < 0)
                                tone += 364;
                            }

                            if (channel->m_adr.m_flags & ASR_FLAG_AMP)
                            {
                                amplifier = (amplifier + channel->m_adr.m_stepADSR[channel->m_adr.m_stage]);
                                if (amplifier >= 0xff)
                                amplifier -= 0xff;
                                if (amplifier < 0)
                                amplifier += 0xff;
                            }

                            if (channel->m_adr.m_flags & ASR_FLAG_FILTER)
                            {
                                lpf.cutoff = (lpf.cutoff + channel->m_adr.m_stepADSR[channel->m_adr.m_stage]);
                                if (lpf.cutoff >= FILTER_LIMITER)
                                lpf.cutoff = FILTER_LIMITER;
                                if (lpf.cutoff < 0)
                                lpf.cutoff = 0;

                                resUp = 1 << ((256-lpf.cutoff)>>6);
                            }

                            if (channel->m_adr.m_flags & ASR_FLAG_PWM)
                            {
                                pulse_width = (pulse_width + (channel->m_adr.m_stepADSR[channel->m_adr.m_stage] * 10));
                                if (pulse_width >= PWM_LIMITER)
                                pulse_width -= PWM_LIMITER;
                                if (pulse_width < 0)
                                pulse_width += PWM_LIMITER;
                            }
                        }
                    }

                    // adsr
                    if (channel->m_adsr.m_stage < channel->m_adsr.m_endState)
                    {
                        int cont = 1;
                        int target = channel->m_adsr.m_targetADSR[channel->m_adsr.m_stage];
                        int delta = 0;
                        channel->m_adsr.m_stageCounter++;

                        // Temporary variable to simplify code
                        delta = channel->m_adsr.m_stepADSR[channel->m_adsr.m_stage];
                        if (
                            ((target != 0) && (
                                    ((delta > 0) && (amplifier >= target)) ||
                                    ((delta < 0) && (amplifier <= target))
                            )) ||
                            (channel->m_adsr.m_stageCounter >= channel->m_adsr.m_numADSR[channel->m_adsr.m_stage])
                           )
                        {
                            channel->m_adsr.m_stageCounter = 0;
                            channel->m_adsr.m_stage++;
                            if (channel->m_adsr.m_stage == channel->m_adsr.m_endState)
                            cont = 0;
                            if (target != 0)
                            amplifier = target;
                        }

                        if (cont)
                        {
                            int wasSigned = channel->m_adsr.m_accumulator[channel->m_adsr.m_stage] < 0;
                            // Compute delta based on accumulators
                            channel->m_adsr.m_accumulator[channel->m_adsr.m_stage] += channel->m_adsr.m_stepADSR[channel->m_adsr.m_stage];
                            delta = channel->m_adsr.m_accumulator[channel->m_adsr.m_stage] >> 16;
                            channel->m_adsr.m_accumulator[channel->m_adsr.m_stage] =  channel->m_adsr.m_accumulator[channel->m_adsr.m_stage] & 0xffff;
                            if (wasSigned)
                              channel->m_adsr.m_accumulator[channel->m_adsr.m_stage] *= -1;

                            amplifier = (amplifier + delta);
                            if (amplifier > 0xff)
                            amplifier = 0xff;
                            if (amplifier < 0)
                            amplifier = 0;

                            if (channel->m_adsr.m_flags & ADSR_FLAG_PITCH)
                            {
                                tone = (tone + delta);
                                if (tone > 364)
                                tone = 364;
                                if (tone < 0)
                                tone = 0;

                            }

                            if (channel->m_adsr.m_flags & ADSR_FLAG_FILTER)
                            {
                                lpf.cutoff = (lpf.cutoff + delta);
                                if (lpf.cutoff > FILTER_LIMITER)
                                lpf.cutoff = FILTER_LIMITER;
                                if (lpf.cutoff < 0)
                                lpf.cutoff = 0;
                                resUp = 1 << ((256-lpf.cutoff)>>6);
                            }

                            if (channel->m_adsr.m_flags & ADSR_FLAG_PWM)
                            {
                                pulse_width = (pulse_width + (delta * 10));
                                if (pulse_width > PWM_LIMITER)
                                pulse_width = PWM_LIMITER;
                                if (pulse_width < 0)
                                pulse_width = 0;
                            }
                        }
                    }
                    else
                    {
                      // Channel is now empty - check if channel queue contains notes
                      RISC_SYNTH *synth = (RISC_SYNTH*)param;
                      if (synth->m_queue[j].m_reader != synth->m_queue[j].m_writer)
                      {
                        int r = synth->m_queue[j].m_reader+1;
                        int osclkp = synth->m_channel[j].m_dco.m_osc_lookup;
                        if (r == MAX_QUEUE_BUFFER)
                        {
                          r = 0;
                        }

                        memcpy(&(synth->m_channel[j]),
                               &(synth->m_queue[j].m_ringBuffer[r]),
                               sizeof(SYNTH_CHANNEL));
                        synth->m_queue[j].m_reader = r;

                        // prserve osc state
                        if (synth->m_channel[j].m_wave != 0)
                        {
                          synth->m_channel[j].m_dco.m_osc_lookup = osclkp;
                        }
                      }
                      else
                      {
                        // Otherwise - finish channel processing
                        length = i;
                        break;
                      }
                   }
                }

                // resup - resonance feedback needs to increase as filter reduces feedback when cutoff is higher.
                // 20 cutoff - *32   5   4     256 - 20 = 236
                // 50 cutoff - *32
                /// 100 cutoff *16   4   7                256
                //  150 cutoff *4
                // 200 cutoff 2     1                     56
                // 255 cutoff 1     0  8                   0
                // Low pass filter
                res = 12 - lpf.resonance;                                        // could move to 256th fractions for pole2 *resup i.e. more points on logscale
                signali = lpf.resonance == 0 ? (signal << 4) : (signal << 4) - ((lpf.pole2*resUp) >> res); // res is logarithmic
                // So as ARM v6 has no integer div - and we want the remainder of the pie for the input pole e.g. 7/8ths and 1/8th cutoff of signal
                // can restate so that the pole is 64 minus the cutoff  shift right 6 i.e. div 64 i.e. 63/64 and 1/64 input
                // This is basically equivalant as the pole is playing catchup - but we have a more linear scale
                // could increase this to 256 (for example)
                // In general div instructions are usually expensive to calculate on any CPU.
                // n.b. 2016 : I could increase the resolution here by 4 bits. Internally filter
                //             range would be 2^12 or 4096 values.
                lpf.pole1 = (lpf.pole1 * (256 - lpf.cutoff) >> 8) + ((signali * lpf.cutoff) >> 8);
                lpf.pole2 = (lpf.pole2 * (256 - lpf.cutoff) >> 8) + ((lpf.pole1 * lpf.cutoff) >> 8);

                {
                    int rout = lpf.pole2 >> 4;

                    if ((channel->m_mode & CHANNEL_MODE_MUTE) == 0)
                    {
                        // stereo pan implemented here.

                      if (watermark == 0)
                      {
                        bufferL->m_data[i] = (rout*channel->m_volumeLeft) >> 8;
                        bufferR->m_data[i] = (rout*channel->m_volumeRight) >> 8;
                      }
                      else
                      {
                        bufferL->m_data[i] += (rout*channel->m_volumeLeft) >>8;
                        bufferR->m_data[i] += (rout*channel->m_volumeRight) >>8;
                      }

                        // The effect channel can have its own pan
                        if (synth_channel->m_effectChannel[j])
                        {
                            if (fxwatermark == 0)
                            synth_channel->m_effectBuffer[i] = rout;
                            else
                            synth_channel->m_effectBuffer[i] += rout;

                        }
                    }
                    xornext[i] = rout;
                }
                length = i+1;

            } // end loop to populate channel buffer


            channel->m_lpf.pole1 = lpf.pole1;
            channel->m_lpf.pole2 = lpf.pole2;
            channel->m_lpf.cutoff = lpf.cutoff;
            channel->m_lpf.resonance = lpf.resonance;
            channel->m_dco.m_osc_lookup = dco.m_osc_lookup;
            channel->m_dco.m_sample_lookup_msw = dco.m_sample_lookup_msw;
            channel->m_amp = amplifier;
            channel->m_tone = tone;
            channel->m_pulse_width = pulse_width;

            if ((channel->m_mode & CHANNEL_MODE_MUTE) == 0)
            {
                if (length>bufferL->m_dataLength )
                {
                    watermark = length;
                    bufferL->m_dataLength = length;
                    bufferR->m_dataLength = length;
                }
            }

            if ((synth_channel->m_effectChannel[j]) && (length > fxwatermark))
            fxwatermark = length;

        } // end channel loop

        // Now process effect buffer with effects algorithms and mix
        // into main buffer

        {
            int i = 0;
            if (synth_channel->m_effects.m_mode != 0)
            {

                for (i = 0; i < lengthbuffer; ++i)
                {
                    // If no data generated then write silence
                    // Assume buffers are in sync
                    if (i >= fxwatermark)
                      synth_channel->m_effectBuffer[i] = 0;
                    if (i >= watermark)
                    {
                      channelBufferL.m_data[i] = 0;
                      channelBufferR.m_data[i] = 0;
                    }

                    if (synth_channel->m_effects.m_mode & EFFECT_MODE_CHORUS)
                    {
                      //  EFFECT_CHORUS *chorus = &(synth_channel->m_effects.m_chorus);
                        U32           p = synth_channel->m_effects.m_chorus.m_line.m_play;
                        U32           r = synth_channel->m_effects.m_chorus.m_line.m_record;

                      //  synth_channel->debug ++;
                     //   synth_channel->debug = (int)&m-(int)&clearBuffer;

                        synth_channel->m_effects.m_chorus.m_line.m_line[r>>18] = synth_channel->m_effectBuffer[i];


                        //synth_channel->debug = 1;



                        synth_channel->m_effectBuffer[i] += synth_channel->m_effects.m_chorus.m_line.m_line[p>>18];

                        synth_channel->m_effects.m_chorus.m_lfoSpeed += synth_channel->m_effects.m_chorus.m_lfoRate *
                          synth_channel->m_effects.m_chorus.m_lfoPolarity;

                        if (synth_channel->m_effects.m_chorus.m_lfoPolarity == 1)
                        {
                          if ((synth_channel->m_effects.m_chorus.m_lfoSpeed) >= 262144)
                            synth_channel->m_effects.m_chorus.m_lfoPolarity = -1;
                        }
                        else if (synth_channel->m_effects.m_chorus.m_lfoPolarity == -1)
                        {
                          if ((synth_channel->m_effects.m_chorus.m_lfoSpeed) <= synth_channel->m_effects.m_chorus.m_lfoDepth)
                            synth_channel->m_effects.m_chorus.m_lfoPolarity = 1;
                        }

                        p += synth_channel->m_effects.m_chorus.m_lfoSpeed;
                        if (p >= 1073479680) p -= 1073479680;
                        r += synth_channel->m_effects.m_chorus.m_lfoSpeed;
                        if (r >= 1073479680) r -= 1073479680;

                        synth_channel->m_effects.m_chorus.m_line.m_play = p;
                        synth_channel->m_effects.m_chorus.m_line.m_record = r;



                    }

                    if (synth_channel->m_effects.m_mode & EFFECT_MODE_DELAY)
                    {
//                        EFFECT_DLINE *dline = &(synth_channel->m_effects.m_delayLine);
                        U32           p = synth_channel->m_effects.m_delayLine.m_play;
                        U32           r = synth_channel->m_effects.m_delayLine.m_record;

                        synth_channel->m_effects.m_delayLine.m_line[r] = synth_channel->m_effectBuffer[i] +
                        ((synth_channel->m_effects.m_delayLine.m_line[p] * synth_channel->m_effects.m_delayLine.m_feedback) >> 8);

                        synth_channel->m_effectBuffer[i] += synth_channel->m_effects.m_delayLine.m_line[p];

                        p++;
                        p = p&0xffff;
                        r++;
                        r = r&0xffff;
                        synth_channel->m_effects.m_delayLine.m_play = p;
                        synth_channel->m_effects.m_delayLine.m_record = r;

                    }

                    if (synth_channel->m_effects.m_mode & EFFECT_MODE_REVERB)
                    {
                      int output = 0;
                      int input = synth_channel->m_effectBuffer[i];
                      int reflect = 0;
                      int ridx = 0;
                      int nline = synth_channel->m_effects.m_reverb.m_numLine;
                      // input effect buffer into reverb DLINEs in parallel
                      // take output of delay lines and mix into filter
                      // feedback filter output into delay lines
                      // write output of reverb into channel buffer
                      for (ridx = 0; ridx < nline; ++ridx)
                      {
                        int p = synth_channel->m_effects.m_reverb.m_line[ridx].m_play;
                        int tmp;

                        tmp = synth_channel->m_effects.m_reverb.m_line[ridx].
                               m_line[p];
                        tmp = (tmp * 14) >> 8;
                        reflect += (tmp * -1);

                        p++;
                        p = p&0xffff;
                        synth_channel->m_effects.m_reverb.m_line[ridx].m_play  = p;
                      }

                      // run the reflection through the filter for phase and sound colouration. n.b. no resonance for simplicity
                      {
                        LPF *lpf = &( synth_channel->m_effects.m_reverb.m_lpf);
                        lpf->pole1 = (lpf->pole1 * (256 - lpf->cutoff) >> 8) + ((reflect * lpf->cutoff) >> 8);
                        lpf->pole2 = (lpf->pole2 * (256 - lpf->cutoff) >> 8) + ((lpf->pole1 * lpf->cutoff) >> 8);


                        reflect = lpf->pole2;
                      }



                      // Record the new input wave and the reflected sound into the delay line
                      for (ridx = 0; ridx < nline; ++ridx)
                      {
                        int r = synth_channel->m_effects.m_reverb.m_line[ridx].m_record;

                         synth_channel->m_effects.m_reverb.m_line[ridx].
                                           m_line[r] = input + reflect;
                         r++;
                         r = r&0xffff;
                         synth_channel->m_effects.m_reverb.m_line[ridx].m_record  = r;
                      }
                      output = reflect * 2;
                      channelBufferL.m_data[i] += output;
                      channelBufferR.m_data[i] += output;

                    }
                    else
                    {
                      channelBufferL.m_data[i] += synth_channel->m_effectBuffer[i];
                      channelBufferR.m_data[i] += synth_channel->m_effectBuffer[i];
                    }

                }
                watermark = lengthbuffer;

            }
        }

        // Copy the synthesiser output to stereo shared sound output.
        // TODO: Pan - i.e. channel buffer will be stereo
        {
            int i = 0;

            int volume = synth_channel->m_masterVolume;
            while ((ptr <= (buffer_end-2)) && (i < watermark))
            {
                int levelL = (channelBufferL.m_data[i] * volume);
                int levelR = (channelBufferR.m_data[i] * volume);

                if (!clearBuffer)
                {
                    ptr[0] = levelR >> 8;
                    ptr++;
                    ptr[0] = levelL >> 8;
                    ptr++;
                }
                else
                {
                    ptr[0] += levelR >> 8;
                    ptr++;
                    ptr[0] += levelL >> 8;
                    ptr++;
                }
                i++;

                // If the audio recorder is m_on then write to buffer
                if (synth_channel->m_recorder.m_on)
                {
                  int p = synth_channel->m_recorder.m_position;
                  synth_channel->m_recorder.m_left[p] =levelL >> 8;
                  synth_channel->m_recorder.m_right[p] =levelR >> 8;
                  synth_channel->m_recorder.m_position += 1;
                  if (synth_channel->m_recorder.m_position >=
                       synth_channel->m_recorder.m_size)
                  {
                    synth_channel->m_recorder.m_on = 0;
                  }
                }



            }
        }
    }

    // The caller copies this to R3
    return flags | 1;
}

