/*
   Risc os Digital Signal Processor
   (C) 2017 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifndef SYNTH_H
#define SYNTH_H

extern unsigned int _toneTable[];
extern unsigned int _sampleFreqTable[];

typedef unsigned long DWORD;
typedef unsigned short WORD;


#define ADSR_FLAG_PITCH  0x1
#define ADSR_FLAG_FILTER 0x2
#define ADSR_FLAG_PWM    0x4

#define ASR_FLAG_AMP     0x8
#define ASR_FLAG_PITCH   0x10
#define ASR_FLAG_FILTER  0x20
#define ASR_FLAG_PWM     0x40

#define ASR_FLAG_LOOP    0x80

// Waveforms
#define WAVEFORM_SAW      0x20
#define WAVEFORM_TRIANGLE 0x40
#define WAVEFORM_NOISE    0x80

// Initially implementing 8 channels
#define MAX_POLY 8

typedef unsigned char U8;
typedef unsigned int  U32;
typedef signed char   S8;

typedef struct _BUFFER_TYPE
{
	short *m_data; //TODO change to S32 - and see if faster
					// Should have 1 typedef for this to make change
					// easier.
	size_t m_size;
	size_t m_dataLength;
} BUFFER_TYPE;

#define MAX_BUFFER (256*1024)
typedef struct _DCO
{
	BUFFER_TYPE m_sample;
	unsigned int m_osc_lookup;
	// If sample playback m_osc_lookup > 256k then update
	// most significant word.
	// Sample playback position = m_sample_lookup_msw * 256k + m_osc_lookup>>14
    unsigned int m_sample_lookup_msw;
} DCO;


typedef enum
{
	adsr_attack,
	adsr_decay,
	adsr_sustain,
	adsr_release
} ADSR_TYPE;


typedef struct _LPF
{
	int pole1;
	int pole2;
	int cutoff;
	int resonance;
	int resUp; // resonance logarithmic multiplier
} LPF;

// TODO: Test whether int is faster than short
//       i.e. whether data alignment affects performance
//       It would also make volume correction i.e. compression easier
//       e.g. if 16 * 32768 then automatically divide down to prevent
//       distortion.


typedef struct _ENVELOPE_ADSR
{
	unsigned int m_flags;
	unsigned int m_stage;
	unsigned int m_stageCounter;
	unsigned int m_counterSpeed;
	unsigned int m_speedCounter;
	unsigned int m_endState;    /* The last state with any data i.e. there may be zero step states in between     */
	int          m_stepADSR[4]; /* Amount of change in each phase (Sustain is always 0)*/
	unsigned int m_numADSR[4]; // Number of steps in 1/100ths of a second
} ENVELOPE_ADSR;

typedef struct _EFFECT_DLINE
{
	signed short m_line[65536]; // TODO check whether 32 bit faster than 16 bit
	U32          m_play;
	U32          m_record;
	int          m_feedback;
} EFFECT_DLINE;

typedef struct _EFFECT_SDLINE
{
	int          m_line[1024];
	U32          m_play;
	U32          m_record;
} EFFECT_SDLINE; // Short delay line

typedef struct _EFFECT_CHORUS
{
	EFFECT_SDLINE m_line;
	int          m_lfo;
	int          m_lfoRate;
	int          m_lfoPolarity;
	int          m_lfoSpeed;
	int          m_lfoDepth;
	LPF          m_filter;
} EFFECT_CHORUS;

typedef struct _EFFECT_DRIVE
{
	int m_gain;
	LPF m_lpf;
} EFFECT_DRIVE;

typedef struct _EFFECT_WARM
{
	EFFECT_SDLINE m_line1;
	EFFECT_SDLINE m_line2;
} EFFECT_WARM;

#define EFFECT_MODE_BOOST  0x00000001
#define EFFECT_MODE_DRIVE  0x00000002
#define EFFECT_MODE_CHORUS 0x00000004
#define EFFECT_MODE_DELAY  0x00000008

typedef struct _EFFECT_PROC
{
	U32          m_mode;

	// Registers and cache
	EFFECT_DLINE  m_delayLine;
	EFFECT_CHORUS m_chorus;
	EFFECT_WARM   m_warm;
	EFFECT_DRIVE  m_drive;

} EFFECTS_PROC;

//
typedef struct
{
    char          m_name[16];
    unsigned char m_wave;
    unsigned char m_options;
    unsigned char m_steptime;
    unsigned char m_cutoff;
    unsigned char m_res;
    unsigned char m_asrStepsAttack;
    unsigned char m_asrStepsSustain;
    unsigned char m_asrStepsRelease;
    signed char   m_asrAttackDelta;
    signed char   m_asrSustainDelta;
    signed char   m_asrReleaseDelta;
    int           m_attack;
    int           m_decay;
    int           m_sustain;
    int           m_release;
} INSTRUMENT_TABLE;

typedef struct
{
    signed short *m_data;
    unsigned int m_length;
} SAMPLE_TABLE;


#define CHANNEL_MODE_SYNC            0x10
#define CHANNEL_MODE_MUTE            0x20
#define CHANNEL_MODE_XOR             0x40

typedef struct _SYNTH_CHANNEL
{
	U8  m_mode;
	DCO m_dco;
	int m_tone;
	U8  m_wave; // 0 indicates sample playback
	int m_amp;
	int m_pulse_width; // TODO move to DCO
	LPF m_lpf;
	ENVELOPE_ADSR m_adr; // TODO fix typo - should be 3 Stage envelope
	ENVELOPE_ADSR m_adsr;
	unsigned int m_prng;
	unsigned int m_noise_throttle;
	int centisecond;



} SYNTH_CHANNEL;



typedef struct _RISC_SYNTH
{
	SYNTH_CHANNEL m_channel[MAX_POLY];
    signed short  m_fillBuffer[44100];
	unsigned char m_effectChannel[MAX_POLY];
    signed short  m_effectBuffer[44100];

    signed short  m_lastChannel[2][44100];

	unsigned int* tonetable;
	unsigned int* sampleFreqTable;
	INSTRUMENT_TABLE m_instrument[256];
	SAMPLE_TABLE     m_sample[256];

    EFFECTS_PROC m_effects;

	 int m_masterVolume;

int debug;
} RISC_SYNTH;

extern unsigned int toneTable[];

extern int sampleFreqTable[];

#define OSC_SIZE 722534400 // i.e. 44100 * 16384 (2 ^ 14  ... the fixed point offset in base 2) - I could go to 2^16 without overflow
#define MAX_TONE        365
#define MAX_AMP         100
#define MAX_FILTER      64 // Consider widening to 256 (128 may be max in practice)
#define MAX_PULSE       361267200
#define SWITCH_TOP_AMP  32000
#define SWITCH_BASE_AMP -32000
// frequency modulation. Axiom = step is proportional to frequency. So if frequency increases by 2. So does step.
// Time is constant. 44100 = 1 second. Envelopes describe time in 100ths of a second.
// So every 441 iterations we can trigger the envelope, thus reducing its footprint by 100 times.
// The envelope may change the pulse width. That's fine too.

#define CENTISECOND 441

// For efficiency - writing whole synth in very small function with 1 loop

// This would be a cool SID like VST actually....

// I think allowing the option for more than 1 modulation source is better..
// e.g. 3 stage env and 4 stage env could modulate pitch.
// The ring mod on the sound channel is processed after this function.
// It is an MS-20 XOR effect. Nice and cheap to run.
// So in effect there are at least 256 possible waves (more in practice due to modulation via tone and XOR).
// multiplied by cutoff & resonance and via envelope modulation. So in practice this should be millions or billions
// of tones.

#define HALF_SAMPLE_RATE    22050
#define SAMPLE_RATE         44100
#define QUARTER_SAMPLE_RATE 11025

#define FILTER_LIMITER 0xff
#define PWM_LIMITER    22050

void buffer_fill(void* param, signed short* buffer_base, signed short* buffer_end,
                 DWORD flags, DWORD sample_freq, DWORD sample_period,
                 DWORD step,  DWORD volume,      void* fill_ptr);


#endif
