// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// adcon.c - A/D conversion
// version 1.00 - 20070525
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define FCY 20000000                    // cycle machine frequency
#include "p30f3014.h"
#include "adcon.h"
#include "buttn.h"
#define defined_in extern
#include "glob.h"
extern int logvalue[];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// hardware AD converters assignment
#define SQWIDE ADCBUFC                  // P1 width
#define PORTAM ADCBUFB                  // P2 portamento
#define LFOFRQ ADCBUFA                  // P3 lfo frequ
#define LFOLEV ADCBUF9                  // P4 lfo level
#define FILFRQ ADCBUF5                  // P5 filter frequ
#define FILRES ADCBUF3                  // P7 filter resonance
#define EN1ATK ADCBUF1                  // P9 env1 ar attack
#define EN1REL ADCBUF7                  // P11 env1 ar release
#define EN1SWP ADCBUF8                  // P13 env1 ar sweep
#define EN2ATK ADCBUF4                  // P6 env2 adsr attack
#define EN2DEC ADCBUF2                  // P8 env2 adsr decay
#define EN2SUS ADCBUF0                  // P10 env2 adsr sustain
#define EN2REL ADCBUF6                  // P12 env2 adsr release
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void adcon_ini(void)                    // A/D conversion initialization
{
// AD configuration
    ADPCFG = 0;                         // AN0-AN12 as analog inputs
    TRISB = 0x1FFF;                     // port B as input
    ADCON1bits.FORM = 0;                // int (0000 dddd dddd dddd)
    ADCON1bits.SSRC = 7;                // 2 T3 contr.; 7 autom.
    ADCON1bits.ASAM = 1;                // auto-start immediately

    ADCON2bits.CSCNA = 1;               // scan for CH0+ S/H for MUX A
    ADCON2bits.SMPI = 15;               // int for each 16th sam/conv
    ADCON2bits.BUFM = 0;                // buffer mode select 0=16 words
    ADCON2bits.ALTS = 0;                // alter.input sample Mode Select

    ADCON3bits.SAMC = 15;               // Auto Sample Time bits
    ADCON3bits.ADRC = 1;                // source ck 0=system 1=internal
    ADCON3bits.ADCS = 63;               // A/D Conv Clock Select bits

// ADCHS: A/D Input Select Register
    ADCHS = 0;                          // clear selection
    ADCHSbits.CH0NA = 0;                // ch.0 neg.input sel.for MUX A

// ADCSSL: A/D Input Scan Select Register    
    ADCSSL = 0x1FFF;                    // scan AN0 thru AN12 giving
                                        // results into ADCBUF0 to ADCBUF12
    IEC0bits.ADIE = 0;                  // disable AD interrupt
    ADCON1bits.ADON = 1;                // enable AD converter
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int adcon_read(void)                    // read analog return has data
{
    if (! ADCON1bits.DONE) return 0;    // analog data not available

    if (g_buttune == TNHALFT)           // if halftone tune selected
    {   g_o1half = SQWIDE;              // P1 dco1 tune
        g_o2half = PORTAM;              // P2 dco2 tune
    }
    else
    if (g_buttune == TNPITCH)           // if pitch tune selected
    {   g_o1ptch = SQWIDE;              // P1 dco1 tune
        g_o2ptch = PORTAM;              // P2 dco2 tune
    }
    else
    {   g_sqwide = SQWIDE;              // P1 width
        g_portam = PORTAM;              // P2 portamento
    }
    g_lfofrq = LFOFRQ;                  // P3 lfo frequ
    g_lfolev = LFOLEV;                  // P4 lfo level
    g_filfrq = FILFRQ;                  // P5 filter frequ
    g_filres = FILRES;                  // P7 filter resonance
    g_en1atk = EN1ATK;                  // P9 env1 ar attack
    g_en1rel = EN1REL;                  // P11 env1 ar release
    g_en1swp = EN1SWP;                  // P13 env1 ar sweep
    g_en2atk = EN2ATK;                  // P6 env2 adsr attack
    g_en2dec = EN2DEC;                  // P8 env2 adsr decay
    g_en2sus = EN2SUS;                  // P10 env2 adsr sustain
    g_en2rel = EN2REL;                  // P12 env2 adsr release

    ADCON1bits.DONE = 0;                // starts AD conversion
    return 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// adcon.h - A/D conversion
// version 1.00 - 20070525
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void adcon_ini(void);                   // A/D conversion initialization
int  adcon_read(void);                  // read analog ports


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// buttn.c - buttons on check and display statuses
// version 1.02 - 20070611 - optimizing buttons debounce
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// Copyright (C) 2007 miguel angel labolida
// This program is under the terms of the GNU General Public License
// buttons 1 to 5 are allocated to RD9, RD3, RA11, RF6, RC13 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define DBOUNC 256                      // debounce counter value
#include "p30f3014.h"
#include "buttn.h"
#include "dsply.h"
#define defined_in extern
#include "glob.h"

static int buttn_led[4] = {8, 4, 2, 1};
// public:
int buttn_change = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void buttn_ini(void)                    // buttons initialization
{
    TRISA |= 0x0800;                    // RA11 is button 3
    TRISC |= 0x2000;                    // RC13 is button 5
    TRISD |= 0x0208;                    // RD9 & RD3 are buttons 1 & 2
    TRISF |= 0x0040;                    // RF6 id button 4
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void buttn_run(void)                    // scanning button states
{
static int debounce = 0;
static int reachtop = 0;

    if ((PORTBUT1WAVE)                  // if button 1 released
    &&  (PORTBUT2MODN)                  // and button 2 released
    &&  (PORTBUT3DCO2)                  // and button 3 released
    &&  (PORTBUT4MIDI)                  // and button 4 released
    &&  (PORTBUT5TUNE))                 // and button 5 released
    {
        if (debounce) debounce --;      // debounce
        else reachtop = 0;
        return;
    }
    else                                // if any pressed
    {   if (reachtop) return;           // if top reached return
        debounce ++;                    // increments value for shoot
        if (debounce < DBOUNC) return;  // if not reached level return
    }

    if (! PORTBUT1WAVE)             // if button 1 pressed
    {   g_butwave ++;               // advance wave
        g_butwave &= 0x03;          // truncate
        dsply_write(DSPLWAVE, buttn_led[g_butwave]); // show
    }

    if (! PORTBUT2MODN)             // if button 2 pressed
    {   g_butmodn ++;               // advance modulation
        g_butmodn &= 0x03;          // truncate
        dsply_write(DSPLMODN, buttn_led[g_butmodn]); // show
    }

    if (! PORTBUT3DCO2)             // if button 3 pressed
    {   g_butdco2 =                 // change status
            (g_butdco2 == DCO2ON)
            ? DCO2OF : DCO2ON;      // toggle status
        dsply_write(DSPLDCO2, g_butdco2); // shows selection
    }

    if ((g_buttune == TUNEOFF)      // ignore if in tune state
    && (! PORTBUT4MIDI))            // if button 4 pressed
    {   g_butmidi ++;               // advance midi channel
        g_butmidi &= 0x000F;        // truncate
        dsply_write(DSPLMIDI, g_butmidi); // shows selection
    }

    if (! PORTBUT5TUNE)             // if button 5 pressed
    {   g_buttune ++;               // advancing selection
        if (g_buttune >= 3) g_buttune = 0; // toggle
        switch(g_buttune) 
        {
        case TUNEOFF: 
            dsply_write(DSPLMIDI, g_butmidi);// shows midi ch
            break;
        case TNHALFT:
            dsply_write(DSPLMIDI, 16); // shows 'H' character
            break;
        case TNPITCH:
            dsply_write(DSPLMIDI, 17); // shows 'P' character
            break;
        }                
    }
    reachtop = 1;                       // flag reach debounce
    buttn_change = 1;                   // flag button change
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void buttn_show(void)                   // shows buttons status
{
    dsply_write(DSPLWAVE, buttn_led[g_butwave]); // shows selection
    dsply_write(DSPLMODN, buttn_led[g_butmodn]); // shows selection
    dsply_write(DSPLDCO2, g_butdco2);   // shows button selection
    dsply_write(DSPLMIDI, g_butmidi);   // shows button selection
    if (g_buttune == TNHALFT) dsply_write(DSPLMIDI, 16);
    if (g_buttune == TNPITCH) dsply_write(DSPLMIDI, 17);
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// buttn.h - buttons on check and display statuses
// version 1.02 - 20070611 - optimizing buttons debounce
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// Copyright (C) 2007 miguel angel labolida
// This program is under the terms of the GNU General Public License
// buttons 1 to 5 are allocated to RD9, RD3, RA11, RF6, RC13 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//#define MODOFF 0
#define MODFRQ 0
#define MODAMP 1
#define MODWID 2
#define MODWAR 3

#define TUNEOFF 0
#define TNHALFT 1
#define TNPITCH 2

#define DCO2OF 0
#define DCO2ON 1


#define PORTBUT1WAVE PORTDbits.RD9
#define PORTBUT2MODN PORTDbits.RD3
#define PORTBUT3DCO2 PORTAbits.RA11
#define PORTBUT4MIDI PORTFbits.RF6
#define PORTBUT5TUNE PORTCbits.RC13

void buttn_ini(void);                   // buttons initialization
void buttn_run(void);                   // scanning button states
void buttn_show(void);                  // shows initial status
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dacon.c - D/A converter
// version 1.00 - 20070525
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "dacon.h"
#define defined_in extern               // defined external
#include "glob.h"                       // global variables
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dacon_ini(void)                    // D/A converter initialization
{
// DA converter init
    TRISD &= 0xFEFB;                    // port D bits 2 and 8 as output
    TRISF &= 0xFFC0;                    // port F bits 0 to 5 as output
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void dacon_write(void)           // write sample to A/D converter
{
    int hi, lo;                         // split for DA converter

    g_sample += 2048;                   // bias for unsigned
    hi = g_sample >> 6;                 // high order 6 bits
    lo = g_sample & 0x003F;             // low order 6 bits

    PORTDbits.RD2 = 0;                  // DA reset clock latch high
    PORTDbits.RD8 = 0;                  // DA reset clock latch low
    PORTF = hi;                         // DA output high part
    PORTDbits.RD2 = 1;                  // DA positive clock latch high
    PORTF = lo;                         // DA output low part
    PORTDbits.RD8 = 1;                  // DA positive clock latch low
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dacon.h - D/A converter
// version 1.00 - 20070525
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dacon_ini(void);                   // D/A converter initialization
void dacon_write(void);                 // write sample to A/D converter
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


/**********************************************************************
* © 2005 Microchip Technology Inc.
*
* FileName:        DataEEPROM.h
* Dependencies:    Header (.h) files if applicable, see below
* Processor:       dsPIC30Fxxxx
* Compiler:        MPLAB® C30 v1.32.00 or higher
* IDE:             MPLAB® IDE v7.20.01 or later
* Dev. Board Used: dsPICDEM 1.1 Development Board
* Hardware Dependencies: None
*
* SOFTWARE LICENSE AGREEMENT:
* Microchip Technology Inc. (“Microchip”) licenses this software to you
* solely for use with Microchip dsPIC® digital signal controller
* products. The software is owned by Microchip and is protected under
* applicable copyright laws.  All rights reserved.
*
* SOFTWARE IS PROVIDED “AS IS.”  MICROCHIP EXPRESSLY DISCLAIMS ANY
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL MICROCHIP
* BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
* PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
* BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
* ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
*
* REVISION HISTORY:
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Author                 Date      Comments on this revision
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Erminio Bonizonni/HV   11/02/05  First release of source file
*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ADDITIONAL NOTES:
*
**********************************************************************/

#define WORD    1
#define ROW     16
#define ALL_EEPROM      0xFFFF
#define ERROREE -1

/*
 * ReadEErow prototype:
 * Parameters Definition:
 * Page:        is the 8 most significant bits of the source address in EEPROM
 * Offset:      is 16 least significant bits of the source address in EEPROM
 * DataOut:     is the 16-bit address of the destination RAM location or array
 * Size:        is the number of words to read from EEPROM and is a value of 1 or 16
 * Return Value:
 * Function returns ERROREE (or -1) if Size is invalid
 */
extern int ReadEE(int Page, int Offset, int* DataOut, int Size);

/*
 * EraseEErow prototype:
 * Parameters Definition:
 * Page:        is the 8 most significant bits of the address in EEPROM to be erased
 * Offset:      is 16 least significant bits of the address in EEPROM to be erased
 * Size:        is the number of words to read from EEPROM and is a value of 1, 16 or
 *              0xFFFF (for erasing ALL EEPROM memory)
 * Return Value:
 * Function returns ERROREE (or -1) if Size is invalid
 */
extern int EraseEE(int Page, int Offset, int Size);

/*
 * WriteEErow prototype:
 * Parameters Definition:
 * Page:        is the 8 most significant bits of the destination address in EEPROM
 * Offset:      is 16 least significant bits of the destination address in EEPROM
 * DataIn:      is the 16-bit address of the source RAM location or array
 * Size:        is the number of words to read from EEPROM and is a value of 1 or 16
 * Return Value:
 * Function returns ERROREE (or -1) if Size is invalid
 */
extern int WriteEE(int* DataIn, int Page, int Offset, int Size);


/**********************************************************************
* © 2005 Microchip Technology Inc.
*
* FileName:        DataEEPROM.s
* Dependencies:    Header (*.inc/.h) files if applicable, see below
* Processor:       dsPIC30Fxxxx
* Compiler:        MPLAB® C30 v1.32.00 or higher
* IDE:             MPLAB® IDE v7.21 or later
* Dev. Board Used: dsPICDEM 1.1 Development Board
* Hardware Dependencies: None
*
* SOFTWARE LICENSE AGREEMENT:
* Microchip Technology Inc. (“Microchip”) licenses this software to you
* solely for use with Microchip dsPIC® digital signal controller
* products. The software is owned by Microchip and is protected under
* applicable copyright laws.  All rights reserved.
*
* SOFTWARE IS PROVIDED “AS IS.”  MICROCHIP EXPRESSLY DISCLAIMS ANY
* WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL MICROCHIP
* BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
* PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
* BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
* ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
*
* REVISION HISTORY:
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Author         Date      Comments on this revision
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* EB/HV          11/02/05  First release of source file
*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ADDITIONAL NOTES:
**********************************************************************/

.include "p30fxxxx.inc"

.equ    EE_WORD_ERASE_CODE, 0x4044
.equ    EE_WORD_WRITE_CODE, 0x4004
.equ    EE_ROW_ERASE_CODE, 0x4045
.equ    EE_ROW_WRITE_CODE, 0x4005
.equ    EE_ALL_ERASE_CODE, 0x4046
.equ    CONFIG_WORD_WRITE_CODE, 0x4006

.global _ReadEE
.global _EraseEE
.global _WriteEE

.section .text
/* DATA EEPROM Read Routines */
_ReadEE:
        push    TBLPAG
        mov     w0, TBLPAG
        cp      w3, #1
        bra     z, L0
        cp      w3, #16
        bra     z, L0
        mov     #-1, w0
        bra     L1
L0:     tblrdl  [w1++],[w2++]
        dec     w3, w3
        bra     nz, L0
L1:     pop     TBLPAG
        return

/* DATA EEPROM Erase Routines */
_EraseEE:
        push.d  w4
        bclr    SR, #Z
        mov     #EE_WORD_ERASE_CODE, W4
        cp      w2, #1
        bra     z, L2
        mov     #EE_ROW_ERASE_CODE, W4
        cp      w2, #16
        bra     z, L2
        mov     #EE_ALL_ERASE_CODE, W4
        mov     #0xFFFF, w5
        cp      w2, w5
        bra     z, L2
        mov     #-1, w0
        pop.d   w4
        return
L2:
        push    TBLPAG
        mov     W0, NVMADRU
        mov     W1, NVMADR
        mov     W4, NVMCON
        push    SR
        mov     #0xE0, W0
        ior     SR
        mov     #0x55, W0
        mov     W0, NVMKEY
        mov     #0xAA, W0
        mov     W0, NVMKEY
        bset    NVMCON, #WR
        nop
        nop
L3:     btsc    NVMCON, #WR
        bra     L3
        clr     w0
        pop     SR
L4:     pop     TBLPAG
        pop.d   w4
        return


/* DATA EEPROM Write Routines */
_WriteEE:
        push    w4
        bclr    SR, #Z
        mov     #EE_WORD_WRITE_CODE, W4
        cp      w3, #1
        bra     z, L5
        mov     #EE_ROW_WRITE_CODE, W4
        cp      w3, #16
        bra     z, L5
        pop     w4
        mov     #-1, w0
        return

L5:     push    TBLPAG
        mov     W1, TBLPAG
        push    W2
L6:     tblwtl  [W0++],[W2++]
        dec     w3, w3
        bra     nz, L6

        mov     W1, NVMADRU
        pop     W2
        mov     W2, NVMADR
        mov     W4, NVMCON
        push    SR
        mov     #0xE0, W0
        ior     SR
        mov     #0x55, W0
        mov     W0, NVMKEY
        mov     #0xAA, W0
        mov     W0, NVMKEY
        bset    NVMCON, #WR
        nop
        nop
L7:     btsc    NVMCON, #WR
        bra     L7
        clr     w0
        pop     SR
        pop     TBLPAG
        pop     w4
        return


.end


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dca.c - digital controlled attenuator
// version 1.00 - 20070604
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "dca.h"
#define defined_in extern               // defined external
#include "glob.h"                       // global variables
extern int logvalue[];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static long dca_value = 0;              // value signal
static int dca_gain = 0;                // value level
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void dca_run(void)               // attenuation function
{
    dca_value = (long)g_sample * (long)dca_gain; // 19 bits value
    g_sample = (int)(dca_value >> 7);   // 19 to 12 bits
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void dca_set(int gain)           // set dca gain
{
    dca_gain = gain;                    // 7 bits value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dca.h - digital controlled attenuator
// version 1.00 - 20070604
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dca_run(void);                     // dca attenuation function
void dca_set(int gain);                 // set attenuation value
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dco.c - digital controlled oscillator
// version 1.04 - 20070612
// version 1.05 - 20070614 - pointed structs to dco and portm
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// direct digital synthesis with 18 bits accumulation
// acumphase    .... .... .... .... .... .... .... ....  32 bits
// deltaphase                    xx xxxx xxxx xxxx xxxx  18 bits
// wavindex                      xx xxxx                  6 bits: 0-63
// wavindex                      xx xx                    4 bits: 0-15 
// wavindex                      xx x                     3 bits: 0-7 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define FCY 20000000                    // cycle machine frequency
#include "p30f3014.h"
#include "string.h"
#include "dco.h"
#include "buttn.h"
#include "minmax.h"
#define defined_in extern               // defined external
#include "glob.h"                       // global variables

extern unsigned int deltaphase[20][12]; // delta table according midi note
extern int sinewave[];                  // sine waveform samples
extern int sawtooth[];                  // sawtooth waveform samples
extern int triangular[];                // triangular waveform samples
extern int expvalue[];                  // exponential
extern int logvalue[];                  // logarithmic
extern int portm_phnew[];               // portm member

static unsigned long dco_acumph[2];     // phase acumulator
static int * dco_pntwave;               // pointer for waveform
// public:
unsigned int dco_deltph[2];             // delta of midi note
int dco_treshsquare;                    // treshold for square width
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void dco_calc_ph(int note)       // delta phase calculation
{
static unsigned int phase;              // phase for note
    unsigned int relphase;              // relative phase for note
    int octave;                         // octave relative number
    int pitch;
    int ntaux;                          // auxiliar for note 
// DCO1
    ntaux = note + (g_o1half >> 7) - 16; // half tone shift
    pitch = g_o1ptch / 205;         // 204.8
    relphase = deltaphase[pitch][ntaux % 12]; 
    octave = (127 - ntaux + 4) / 12;    // determine octave
    phase = relphase >> octave;         // deltaphase result
    portm_phnew[0] = phase;
// DCO2
    ntaux = note + (g_o2half >> 7) - 16; // half tone shift
    pitch = g_o2ptch / 205;         // 204.8
    relphase = deltaphase[pitch][ntaux % 12]; 
    octave = (127 - ntaux + 4) / 12;    // determine octave
    phase = relphase >> octave;         // deltaphase result
    portm_phnew[1] = phase;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void dco_run(void)               // runs dco and set g_sample
{
//#define SHFT 12                         // delta phase bits - 64 samples
//#define MASK 0x003F                     // max.index for 64 samples
#define SHFT 14                         // delta phase bits - 16 samples
#define MASK 0x000F                     // max.index for 16 samples
    int i, j;                           // wavetable indexes
    int sample, aux;                    // wavetable sample
    int fractn;                         // fractional part of acumphase
    long linint;                        // linear interpolation value
// DCO1
    dco_acumph[0] += dco_deltph[0];     // phase advancing
    dco_acumph[0] &= 0x0003FFFF;        // truncate over 18 bits
    i = dco_acumph[0] >> SHFT;          // 6 bits hi for 64 samp 14 bits
    // linear interpolation
    fractn = dco_acumph[0] - (i << SHFT); // acum frac for 64 samp 14 bits
    j = (i + 1) & MASK;                 // next sample index
    linint = dco_pntwave[j] - dco_pntwave[i]; // interval for interpolate
    linint *= fractn;                   // fraction
    linint = linint >> SHFT;            // convert 64 samp 14 bits
    sample = dco_pntwave[i] + linint;   // sample value
    // end of linear interpolation
    sample = sample >> 2;               // reduce 14 to 12 bits
    if (g_butwave == SQU)               // if square
    {
        sample = sample * 4 + dco_treshsquare;
        sample = min(sample, 2000);
        sample = max(sample, -2000);
    }
// DCO2
    aux = sample;                       // save DCO1 sample
    dco_acumph[1] += dco_deltph[1];     // phase advancing
    dco_acumph[1] &= 0x0003FFFF;        // truncate over 18 bits
    i = dco_acumph[1] >> SHFT;          // 6 bits hi for 64 samp 14 bits
    // linear interpolation
    fractn = dco_acumph[1] - (i << SHFT); // acum frac for 64 samp 14 bits
    j = (i + 1) & MASK;                 // next sample index
    linint = dco_pntwave[j] - dco_pntwave[i]; // interval for interpolate
    linint *= fractn;                   // fraction
    linint = linint >> SHFT;            // convert 64 samp 14 bits
    sample = dco_pntwave[i] + linint;   // sample value
    // end of linear interpolation
    sample = sample >> 2;               // reduce 14 to 12 bits
    if (g_butwave == SQU)               // if square
    {
        sample = sample * 4 + dco_treshsquare;
        sample = min(sample, 2000);
        sample = max(sample, -2000);
    }
    g_sample = (g_butdco2 == DCO2ON)
        ? (sample + aux) >> 2           // 11 bits output
        : aux >> 1;                     // 11 bits output
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dco_set_wave(void)                 // set waveform
{
    switch (g_butwave)
    {
    case SIN: dco_pntwave = sinewave; break;
    case SAW: dco_pntwave = sawtooth; break;
    case TRI: dco_pntwave = triangular; break;
    case SQU: dco_pntwave = triangular; break;
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dco.h - digital controlled oscillator
// version 1.04 - 20070612
// version 1.05 - 20070614 - pointed structs to dco and portm
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// direct digital synthesis with 18 bits accumulation
// acumphase    .... .... .... .... .... .... .... ....  32 bits
// deltaphase                    xx xxxx xxxx xxxx xxxx  18 bits
// wavindex                      xx xxxx                  6 bits: 0-63
// wavindex                      xx xx                    4 bits: 0-15 
// wavindex                      xx x                     3 bits: 0-7 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define SAW 0
#define TRI 1 
#define SIN 2
#define SQU 3
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dco_calc_ph(int note);             // deltaphase calculation
void dco_run(void);                     // runs dco and set g_sample
void dco_set_wave(void);                // set waveform
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dsply.c - display functions for hardware version 1.03
// version 1.01 - 20070601
// version 1.07 - 20070615 - clear overrun - optimizing
// display hardware is a 16 bits shift register positive clock 
// that controls 9 leds and a 7 segment display 
// clock is RD0, data is RD1
// first bits are for leds 1 to 8
// following 7 bits are for 7 segments display
// last bit is for lower led
// function use: dsply_write(int numb, int msg);
// numb: display number DSPLWAVE, DSPLMODN, DSPLDCO2, DSPLMIDI 
// msg: value to be displayed 0 to F, H, t and blank
//
// internals
// dispbuffer layout
// D3= ===========D7SEG==========  ======D2======  ======D1======
// d15 d14 d13 d12 d11 d10 d9  d8  d7  d6  d5  d4  d3  d2  d1  d0
// L9   E   D   C   A   B   F   G  L5  L6  L7  L8  L4  L3  L2  L1   
//
// characters representation in 7 segments display
// ver 3 7654 3210
//   dig  EDC ABFG  hex    dig  EDC ABFG  hex    dig  EDC ABFG  hex
//   '0' x000 0001  0x01   '8' x000 0000  0x00   'H' x010 1000  0x28
//   '1' x110 1011  0x6B   '9' x100 0000  0x40   'P' x011 0000  0x30
//   '2' x001 0010  0x12   'A' x010 0000  0x20   't' x001 1100  0x1C
//   '3' x100 0010  0x42   'b' x000 1100  0x0C   ' ' x111 1111  0x7F
//   '4' x110 1000  0x68   'C' x001 0101  0x15
//   '5' x100 0100  0x44   'd' x000 1010  0x0A
//   '6' x000 0100  0x04   'E' x001 0100  0x14
//   '7' x110 0011  0x63   'F' x011 0100  0x34
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "dsply.h"
#include "buttn.h"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dsply_ini(void)                    // display initialization
{
    TRISD &= 0xFFFC;                    // port D bits 0 & 1 as output
    PORTD = 0x0001;                     // clock high
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void dsply_write (int numb, int msg)    // display write
{
static unsigned int dispbuffer = 0xFFFF;// all displays off
static unsigned int hexchar[20] =       // 0 to F, H, P, t, and ' '
{   0x01,  0x6B,  0x12,  0x42,  0x68,  0x44,  0x04,  0x63, // '0'to'7'
    0x00,  0x40,  0x20,  0x0C,  0x15,  0x0A,  0x14,  0x34, // '8'to'F'
    0x28,  0x30,  0x1C,  0x7F};         // 'H', 'P', 't', ' '
    int  i;                             // buffer index
    unsigned int savebuffer;            // buffer save area
    unsigned int databit;               // data bit to transfer
    switch(numb)
    {
    case DSPLWAVE:                      // DCO wave display 1
        savebuffer = 0;
        for (i = 0; i < 4; i ++)        // inverts bits order
        {
            savebuffer = savebuffer << 1;
            databit = msg & 0x0001;
            savebuffer |= databit;
            msg = msg >> 1;
        }
        msg = savebuffer;
        dispbuffer &= 0xFFF0;           // clear nibble
        msg |= 0xFFF0;                  // clear unused message part
        dispbuffer |= ~msg;             // load into buffer
        break;
    case DSPLMODN:                      // modulation display 2
        dispbuffer &= 0xFF0F;           // clear nibble
        msg = msg << 4;                 // positioning in nibble
        msg |= 0xFF0F;                  // clear unused message part
        dispbuffer |= ~msg;             // load into buffer
        break;
    case DSPLDCO2:                      // dco on off display
        dispbuffer &= 0x7FFF;           // clear bit
        if (msg == DCO2OF)              // if off
           dispbuffer |= 0x8000;        // reset bit into buffer
        break;
    case DSPLMIDI:                      // 7 segment display
        msg = hexchar[msg];
        msg = msg << 8;                 // positioning in nibble
        msg &= 0x7F00;                  // clear low order
        dispbuffer &= 0x80FF;           // clear nibbles
        dispbuffer |= msg;              // load into buffer
        break;
    }
    savebuffer = dispbuffer;            // save
    for (i = 0; i < 16; i ++)           // serial transmission
    {
        databit = dispbuffer & 0x0001;  // low order bit
        PORTDbits.RD0 = 0;              // clock 0
        PORTDbits.RD1 = databit;        // data to be transmitted
        msg = 0;                        // force delay
        PORTDbits.RD0 = 1;              // positive clock pulse
        dispbuffer = dispbuffer >> 1;   // next bit
    }
    dispbuffer = savebuffer;            // restore
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// dsply.h - display functions for hardware version 1.03
// version 1.01 - 20070601
// version 1.07 - 20070615 - clear overrun - optimizing
// display hardware is a 16 bits shift register positive clock 
// that controls 9 leds and a 7 segment display 
// clock is RD0, data is RD1
// first bits are for leds 1 to 8
// following 7 bits are for 7 segments display
// last bit is for lower led
// function use: dsply_write(int numb, int msg);
// numb: display number DSPLWAVE, DSPLMODN, DSPLDCO2, DSPLMIDI 
// msg: value to be displayed 0 to F, H, t and clear
//
// internals
// dispbuffer layout
// D3= ===========D7SEG==========  ======D2======  ======D1======
// d15 d14 d13 d12 d11 d10 d9  d8  d7  d6  d5  d4  d3  d2  d1  d0
// L9   E   D   C   A   B   F   G  L5  L6  L7  L8  L4  L3  L2  L1   
//
// characters representation in 7 segments display
// ver 3 7654 3210
//   dig  EDC ABFG  hex    dig  EDC ABFG  hex    dig  EDC ABFG  hex
//   '0' x000 0001  0x01   '8' x000 0000  0x00   'H' x010 1000  0x28
//   '1' x110 1011  0x6B   '9' x100 0000  0x40   'P' x011 0000  0x30
//   '2' x001 0010  0x12   'A' x010 0000  0x20   't' x001 1100  0x1C
//   '3' x100 0010  0x42   'b' x000 1100  0x0C   ' ' x111 1111  0x7F
//   '4' x110 1000  0x68   'C' x001 0101  0x15
//   '5' x100 0100  0x44   'd' x000 1010  0x0A
//   '6' x000 0100  0x04   'E' x001 0100  0x14
//   '7' x110 0011  0x63   'F' x011 0100  0x34
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define DSPLWAVE 0
#define DSPLMODN 1
#define DSPLDCO2 2
#define DSPLMIDI 3

void dsply_ini(void);                   // display initialization
void dsply_write (int numb, int msg);   // display write
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// env.c - envelopes sampled by env_adsr_run() and env_ar_run()
// version 1.02 - 20070605
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "env.h"
#include "minmax.h"
#define defined_in extern               // defined externally
#include "glob.h"                       // global variables
extern int logvalue[];
extern int expvalue[];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int env_en1atk;                  // P9 env1 ar attack
static int env_en1rel;                  // P11 env1 ar release
static int env_en2atk;                  // P6 env2 adsr attack
static int env_en2dec;                  // P8 env2 adsr decay
static int env_en2sus;                  // P10 env2 adsr sustain
static int env_en2rel;                  // P12 env2 adsr release
static long env_count_adsr = 0;         // value counter adsr
static int env_step_adsr = 0;           // state adsr
static int env_notes_on = 0;            // active notes counter
static long env_count_ar = 0;           // value counter ar
static int env_step_ar = 0;             // state ar
// public:
int env_en1swp;                         // P13 env1 ar sweep
int env_value_ar = 0;                   // value shape ar
int env_value_adsr;                     // value shape adsr
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void env_adsr_off(void)          // ADSR stop
{
    env_notes_on --;                    // sinalize notes active
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void env_adsr_on(void)           // ADSR start
{
    env_notes_on ++;                    // sinalize notes active
    env_step_adsr = ATK;                // starts attack step
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void env_adsr_run(void)          // ADSR envelope shape step
{
    switch(env_step_adsr)               // analize step
    {
    case STOP: break;                   // inactive
    case ATK:                           // attack
        env_count_adsr += env_en2atk;
        env_value_adsr = env_count_adsr >> 9;
        if (env_value_adsr >= ENVMAX)   // if reach the top
        {   env_value_adsr = ENVMAX;    // ensure level    
            env_step_adsr = DEC;        // set decay status
        }
        break;
    case DEC:                           // decay
        env_count_adsr -= env_en2dec;
        env_value_adsr = env_count_adsr >> 9;
        if (env_value_adsr <= env_en2sus)// if reach the sustain
        {   env_value_adsr = env_en2sus;// ensure level    
            env_step_adsr = SUS;        // set sustain status
        }
        break;
    case SUS:                           // sustain
        if (! env_notes_on)             // if no notes active
            env_step_adsr = REL;        // start release step
        break;
    case REL:                           // release
        env_count_adsr -= env_en2rel;
        env_value_adsr = env_count_adsr >> 9;
        if (env_value_adsr <= 0)        // if reach the floor
        {   env_value_adsr = 0;         // ensure level
            env_count_adsr = 0;    
            env_step_adsr = STOP;       // set end status
        }
        break;
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void env_adsr_set(void)          // ser ADSR values
{
    env_en2atk = expvalue[g_en2atk >> 5] + 1; // P6 env2 adsr attack
    env_en2dec = expvalue[g_en2dec >> 5] + 1; // P8 env2 adsr decay
    env_en2sus = g_en2sus >> 5;               // P10 env2 adsr sustain
    env_en2rel = expvalue[g_en2rel >> 5] + 1; // P12 env2 adsr release
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline int  env_ar_get(void)            // returns AR shape value
{
    return env_value_ar * env_en1swp / ENVMAX; // returns AR shape val
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void env_ar_on(void)             // AR start
{
    env_value_ar = 0;                   // trunc possible running shape
    env_count_ar = 0;                   // initialize
    env_step_ar = ATK;                  // starts attack step
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void env_ar_run(void)            // AR envelope shape step
{
    switch(env_step_ar)                 // analize step
    {
    case STOP: break;                   // inactive
    case ATK:                           // attack
        env_count_ar += env_en1atk;
        env_value_ar = env_count_ar >> 9;
        if (env_value_ar >= ENVMAX)     // if reach the top
        {   env_value_ar = ENVMAX;      // ensure level    
            env_step_ar = REL;          // set release status
        }
        break;
    case REL:                           // release
        env_count_ar -= env_en1rel;
        env_value_ar = env_count_ar >> 9;
        if (env_value_ar <= 0)          // if reach the floor
        {   env_value_ar = 0;           // ensure level
            env_count_ar = 0;    
            env_step_ar = STOP;         // set end status
        }
        break;
    }
    env_value_ar = (env_value_ar * env_en1swp) >> 7; // set AR shape
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void env_ar_set()                       // ser ARS values from global
{
    env_en1atk = expvalue[g_en1atk >> 5] + 1; // P6 env2 ar attack
    env_en1rel = expvalue[g_en1rel >> 5] + 1; // P12 env2 ar release
    env_en1swp = ENVMAX - (g_en1swp >> 4); // P13 env1 ar sweep
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// env.h - envelopes sampled by timer1 at 20 KHz
// version 1.02 - 20070605
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void env_adsr_off(void);                // ADSR stop
void env_adsr_on(void);                 // ADSR start
void env_adsr_run(void);                // ADSR envelope shape step
void env_adsr_set(void);                // set ADSR values from gobal
void env_ar_on(void);                   // AR start
void env_ar_run(void);                  // AR envelope shape step
void env_ar_set(void);                  // set ARS values
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define STOP 0                          // envelope status stop
#define ATK 1                           // envelope status attack
#define DEC 2                           // envelope status decay
#define SUS 3                           // envelope status sustain
#define REL 4                           // envelope status release
#define ENVMAX 127                      // maximum envelope value
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// logen - logarithmic table generator - ver.1.01 - 20070602
// Copyright (C) 2007  miguel angel labolida
// This program is under the terms of the GNU General Public License
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//          output file name with extension: expt.c
//                               step in db: 0.570000
//            mode A:ascending D:descending: D
//                       resolution in bits: 12
//                         samples quantity: 128
//                            resol.max.val: 4096
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     unsigned int expvalue[128] = {
        0x0FFF, 0x0EFA, 0x0E07, 0x0D23, 0x0C4D, 0x0B85, 0x0ACA, 0x0A1A, 
        0x0976, 0x08DC, 0x084C, 0x07C5, 0x0747, 0x06D0, 0x0662, 0x05FA, 
        0x0599, 0x053E, 0x04E8, 0x0498, 0x044E, 0x0408, 0x03C6, 0x0389, 
        0x034F, 0x0319, 0x02E7, 0x02B8, 0x028C, 0x0262, 0x023B, 0x0217, 
        0x01F5, 0x01D5, 0x01B7, 0x019B, 0x0181, 0x0169, 0x0152, 0x013C, 
        0x0128, 0x0115, 0x0104, 0x00F3, 0x00E4, 0x00D5, 0x00C8, 0x00BB, 
        0x00AF, 0x00A4, 0x0099, 0x0090, 0x0086, 0x007E, 0x0076, 0x006E, 
        0x0067, 0x0061, 0x005B, 0x0055, 0x004F, 0x004A, 0x0046, 0x0041, 
        0x003D, 0x0039, 0x0035, 0x0032, 0x002F, 0x002C, 0x0029, 0x0026, 
        0x0024, 0x0022, 0x001F, 0x001D, 0x001B, 0x001A, 0x0018, 0x0016, 
        0x0015, 0x0014, 0x0012, 0x0011, 0x0010, 0x000F, 0x000E, 0x000D, 
        0x000C, 0x000B, 0x000B, 0x000A, 0x0009, 0x0009, 0x0008, 0x0008, 
        0x0007, 0x0007, 0x0006, 0x0006, 0x0005, 0x0005, 0x0005, 0x0004, 
        0x0004, 0x0004, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, 
        0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0001, 0x0001, 0x0001, 
        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 
        };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// filt.c - simplest IIR with resonance - fixed point arithmetic
// version 1.01 - 20070603
// version 1.07 - 20070615 - clear overrun - optimizing
// set feedback amount f given m and q between 0 and 1
//   f = q + q/(1.0 - m);
// for each sample...
//   y[i-1] = y[i-1] + m * (x[i] - y[i-1] + f * (y[i-1] - y[i]));
//   y[i] = y[i] + m * (y[i-1] - y[i]);
// to symbolic pseudo-code: 
//   y[i-1] = y1;  y[i] = y0;  x[i] = input;  m = filt_frq;  f = filt_fbk
//   y1 += filt_frq * (input - y1 + filt_fbk * (y1 - y0));
//   y0 += filt_frq * (y1 - y0);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "filt.h"
#include "minmax.h"
#define defined_in extern               // defined externally
#include "glob.h"                       // global variables

static unsigned int filt_frq;           // IIR fracionary freq
static int filt_fbk;                    // feedback coeficient
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void filt_run(void)              // values +/- 2048
{
static int y0 = 0;                      // sample y[i]
static int y1 = 0;                      // sample y[i-1]
    long aux;
    int feedback;

    aux = filt_fbk;                     // prepare for
    aux *= (y1 - y0);                   // feedback calc
    aux = aux >> 10;                    // divides by 1024
    aux = min(aux, 1023);               // prevents saturation
    aux = max(aux, -1023);              // prevents saturation
    feedback = aux;
    aux = filt_frq;
    aux *= (g_sample - y1 + feedback);
    aux = aux >> 10;                    // divides by 1024
    y1 += aux;
    aux = filt_frq;
    aux *= (y1 - y0);
    aux = aux >> 10;                    // divides by 1024
    y0 += aux;

    g_sample = y0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void filt_set(int env_ar)               // frequency & resonance set
{                                       // values from 0 to 4095
#define MAXFRQ 820
    long aux, fee;
    unsigned int q;                     // resonance coeficient

    filt_frq = g_filfrq / 5;            // fract.of 1024 limit.to 819
    filt_frq += env_ar;                 // AR modulation
    filt_frq = min(filt_frq, MAXFRQ);   // limit the range again
    q = g_filres >> 2;                  // resonance as fract 1024

//  filt_fbk = g_q + g_q / (1 - filt_frq); <- set feedback coef.
    fee = q;                            // prepare into long for
    fee <<= 10;                         // multiplying by 1024
    aux = fee / (1024 - filt_frq);
    filt_fbk = q + aux;                 // feedback coef.fract 1024
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// filt.h - simplest IIR with resonance - fixed point arithmetic
// version 1.01 - 20070603
// version 1.07 - 20070615 - clear overrun - optimizing
// set feedback amount f given m and q between 0 and 1
//   f = q + q/(1.0 - m);
// for each sample...
//   y[i-1] = y[i-1] + m * (x[i] - y[i-1] + f * (y[i-1] - y[i]));
//   y[i] = y[i] + m * (y[i-1] - y[i]);
// to symbolic pseudo-code: 
//   y[i-1] = y1;  y[i] = y0;  x[i] = input;  m = filt_frq;  f = filt_fbk
//   y1 += filt_frq * (input - y1 + filt_fbk * (y1 - y0));
//   y0 += filt_frq * (y1 - y0);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void filt_run(void);                    // filter function
void filt_set(int env_ar);              // frequency resonance setting
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// dtgen - delta phase table generator - ver.1.06 - 20070612
// Copyright (C) 2007  miguel angel labolida
// This program is under the terms of the GNU General Public License
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//                      half tone divisions: 10
//        note frequ.reference (220 to 440): 330
//          output file name with extension: freq.c
//                        quantity of notes: 2
//                       resolution in bits: 18
//                         sample frequency: 25000
//                            resol.max.val: 262144
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     unsigned int deltaphase[20][12] = {
        {0x6610,  0x6C22,  0x7290,  0x7960,  0x8098,  0x883D, 
         0x9057,  0x98EC,  0xA204,  0xABA7,  0xB5DC,  0xC0AC},
        {0x66A8,  0x6CC2,  0x733A,  0x7A14,  0x8156,  0x8907, 
         0x912D,  0x99CF,  0xA2F5,  0xACA5,  0xB6E9,  0xC1CA},
        {0x6740,  0x6D64,  0x73E5,  0x7AC9,  0x8216,  0x89D2, 
         0x9204,  0x9AB3,  0xA3E6,  0xADA5,  0xB7F9,  0xC2E9},
        {0x67D9,  0x6E06,  0x7491,  0x7B7F,  0x82D7,  0x8A9F, 
         0x92DD,  0x9B99,  0xA4D9,  0xAEA7,  0xB909,  0xC40A},
        {0x6873,  0x6EA9,  0x753E,  0x7C36,  0x8399,  0x8B6C, 
         0x93B7,  0x9C7F,  0xA5CE,  0xAFAA,  0xBA1C,  0xC52D},
        {0x690E,  0x6F4D,  0x75EB,  0x7CEE,  0x845C,  0x8C3B, 
         0x9492,  0x9D67,  0xA6C4,  0xB0AE,  0xBB30,  0xC651},
        {0x69AA,  0x6FF2,  0x769A,  0x7DA8,  0x8521,  0x8D0B, 
         0x956E,  0x9E51,  0xA7BB,  0xB1B4,  0xBC45,  0xC777},
        {0x6A46,  0x7098,  0x774A,  0x7E62,  0x85E6,  0x8DDC, 
         0x964C,  0x9F3C,  0xA8B4,  0xB2BC,  0xBD5D,  0xC89F},
        {0x6AE4,  0x713F,  0x77FB,  0x7F1D,  0x86AD,  0x8EAF, 
         0x972B,  0xA028,  0xA9AE,  0xB3C5,  0xBE75,  0xC9C9},
        {0x6B82,  0x71E7,  0x78AD,  0x7FDA,  0x8774,  0x8F82, 
         0x980B,  0xA115,  0xAAA9,  0xB4CF,  0xBF90,  0xCAF4},
        {0x6C22,  0x7290,  0x7960,  0x8098,  0x883D,  0x9057, 
         0x98EC,  0xA204,  0xABA7,  0xB5DC,  0xC0AC,  0xCC21},
        {0x6CC2,  0x733A,  0x7A14,  0x8156,  0x8907,  0x912D, 
         0x99CF,  0xA2F5,  0xACA5,  0xB6E9,  0xC1CA,  0xCD50},
        {0x6D64,  0x73E5,  0x7AC9,  0x8216,  0x89D2,  0x9204, 
         0x9AB3,  0xA3E6,  0xADA5,  0xB7F9,  0xC2E9,  0xCE80},
        {0x6E06,  0x7491,  0x7B7F,  0x82D7,  0x8A9F,  0x92DD, 
         0x9B99,  0xA4D9,  0xAEA7,  0xB909,  0xC40A,  0xCFB2},
        {0x6EA9,  0x753E,  0x7C36,  0x8399,  0x8B6C,  0x93B7, 
         0x9C7F,  0xA5CE,  0xAFAA,  0xBA1C,  0xC52D,  0xD0E6},
        {0x6F4D,  0x75EB,  0x7CEE,  0x845C,  0x8C3B,  0x9492, 
         0x9D67,  0xA6C4,  0xB0AE,  0xBB30,  0xC651,  0xD21C},
        {0x6FF2,  0x769A,  0x7DA8,  0x8521,  0x8D0B,  0x956E, 
         0x9E51,  0xA7BB,  0xB1B4,  0xBC45,  0xC777,  0xD354},
        {0x7098,  0x774A,  0x7E62,  0x85E6,  0x8DDC,  0x964C, 
         0x9F3C,  0xA8B4,  0xB2BC,  0xBD5D,  0xC89F,  0xD48D},
        {0x713F,  0x77FB,  0x7F1D,  0x86AD,  0x8EAF,  0x972B, 
         0xA028,  0xA9AE,  0xB3C5,  0xBE75,  0xC9C9,  0xD5C8},
        {0x71E7,  0x78AD,  0x7FDA,  0x8774,  0x8F82,  0x980B, 
         0xA115,  0xAAA9,  0xB4CF,  0xBF90,  0xCAF4,  0xD705},
        };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// glob.h - global variables
// version 1.00 - 20070606
// version 1.05 - 20070614 - pointed structs to dco and portm
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                        // buttons
defined_in int g_butwave;               // waveform selection
defined_in int g_butmodn;               // modulation
defined_in int g_butdco2;               // DCO2 on/off
defined_in int g_butmidi;               // midi channel advance
defined_in int g_buttune;               // tune: halftone/pitch/off

                                        // potentiometers
defined_in int g_sqwide;                // p1 width
defined_in int g_o1half;                // p1 dco1 halftone tune
defined_in int g_o1ptch;                // p1 dco1 pitch tune
defined_in int g_portam;                // p2 portamento
defined_in int g_o2half;                // p2 dco2 halftone tune
defined_in int g_o2ptch;                // p2 dco2 pitch tune
defined_in int g_lfofrq;                // p3 lfo frequ
defined_in int g_lfolev;                // p4 lfo level
defined_in int g_filfrq;                // p5 filter frequ
defined_in int g_filres;                // p7 filter resonance
defined_in int g_en1atk;                // p9 env1 ar attack
defined_in int g_en1rel;                // p11 env1 ar release
defined_in int g_en1swp;                // p13 env1 ar sweep
defined_in int g_en2atk;                // p6 env2 adsr attack
defined_in int g_en2dec;                // p8 env2 adsr decay
defined_in int g_en2sus;                // p10 env2 adsr sustain
defined_in int g_en2rel;                // p12 env2 adsr release

defined_in int g_note;                  // auxiliar for midi note
defined_in int g_velo;                  // auxiliar for midi velocity
defined_in int g_sample;                // output sample
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// lfo.c - oscillator sampled at 10KHz
// version 1.00 - 20070603
// version 1.07 - 20070615 - clear overrun - optimizing
// 20s to 10ms - 0.05 to 100hz
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "lfo.h"
#define defined_in extern               // defined externally
#include "glob.h"                       // global variables
extern int logvalue[];
extern int sinewave[];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int lfo_level = 0;               // lfo level
static int lfo_delta;
static unsigned long lfo_acum = 0;      // phase acum
// public:
int lfo_value = 0;                      // value shape lfo
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void lfo_run(void)               // lfo sampling
{
//#define SHFT 12                         // delta phase bits - 64 samples
//#define MASK 0x003F                     // max.index for 64 samples

#define SHFT 14                         // delta phase bits - 16 samples
#define MASK 0x000F                     // max.index for 16 samples
    int i, j;                           // wavetable indexes
    int sample;                         // wavetable sample
    int fractn;                         // fractional part of acumphase
    long linint;                        // linear interpolation value

    lfo_acum += lfo_delta;              // phase advancing
    lfo_acum &= 0x0003FFFF;             // truncate over 18 bits
    i = lfo_acum >> SHFT;               // bits hi for n samp 14 bits
    // linear interpolation
    fractn = lfo_acum - (i << SHFT);    // acum frac for n samp 14 bits
    j = (i + 1) & MASK;                 // next sample index
    linint = sinewave[j] - sinewave[i]; // interval for interpolate
    linint *= fractn;                   // fraction
    linint = linint >> SHFT;            // convert 64 samp 14 bits
    sample = sinewave[i] + linint;      // sample value
    // end of linear interpolation
    sample = sample >> 2;               // reduce 14 to 12 bits

    linint = (long)sample * (long)lfo_level; // 17 bits value
    lfo_value = (int)(linint >> 10);    // 17 to 7 bits - 128 values
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void lfo_set(void)               // set frequency and level
{
    lfo_delta = logvalue[g_lfofrq >> 5] + 1; // avoiding zero
    lfo_level = g_lfolev >> 7;          // 5 bits 32 levels
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// lfo.h - oscillator sampled at 10KHz
// version 1.00 - 20070603
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void lfo_run(void);                     // lfo sampling
void lfo_set(void);                     // set frequency and level
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// logen - logarithmic table generator - ver.1.01 - 20070602
// Copyright (C) 2007  miguel angel labolida
// This program is under the terms of the GNU General Public License
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//          output file name with extension: logt.c
//                               step in db: 0.570000
//            mode A:ascending D:descending: A
//                       resolution in bits: 12
//                         samples quantity: 128
//                            resol.max.val: 4096
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     unsigned int logvalue[128] = {
        0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 
        0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 
        0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0004, 0x0004, 
        0x0004, 0x0005, 0x0005, 0x0005, 0x0006, 0x0006, 0x0007, 0x0007, 
        0x0008, 0x0008, 0x0009, 0x0009, 0x000A, 0x000B, 0x000B, 0x000C, 
        0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0014, 0x0015, 
        0x0016, 0x0018, 0x001A, 0x001B, 0x001D, 0x001F, 0x0022, 0x0024, 
        0x0026, 0x0029, 0x002C, 0x002F, 0x0032, 0x0035, 0x0039, 0x003D, 
        0x0041, 0x0046, 0x004A, 0x004F, 0x0055, 0x005B, 0x0061, 0x0067, 
        0x006E, 0x0076, 0x007E, 0x0086, 0x0090, 0x0099, 0x00A4, 0x00AF, 
        0x00BB, 0x00C8, 0x00D5, 0x00E4, 0x00F3, 0x0104, 0x0115, 0x0128, 
        0x013C, 0x0152, 0x0169, 0x0181, 0x019B, 0x01B7, 0x01D5, 0x01F5, 
        0x0217, 0x023B, 0x0262, 0x028C, 0x02B8, 0x02E7, 0x0319, 0x034F, 
        0x0389, 0x03C6, 0x0408, 0x044E, 0x0498, 0x04E8, 0x053E, 0x0599, 
        0x05FA, 0x0662, 0x06D0, 0x0747, 0x07C5, 0x084C, 0x08DC, 0x0976, 
        0x0A1A, 0x0ACA, 0x0B85, 0x0C4D, 0x0D23, 0x0E07, 0x0EFA, 0x0FFF, 
        };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// midi.c - functions for MIDI messages received from UART
// version 1.00 - 20070525
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define FCY 20000000                    // cycle machine frequency
#define NOTE_ON     0x0090              // midi command note on
#define NOTE_OFF    0x0080              // midi command note off
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "midi.h"
#define defined_in extern               // defined externally
#include "glob.h"                       // global variables
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void midi_ini(void)                     // midi initialization
{
    U1MODEbits.UARTEN = 1;              // enable UART1
    U1MODEbits.ALTIO = 1;               // alternate RX to pin 16
    U1BRG = 0;
    U1BRG = ((FCY / 31250) / 16) - 1;   // calculate baud register
    IEC0bits.U1RXIE = 0;                // disable reception interrupt
    U1MODEbits.PDSEL = 0;               // parity bits 2 and 1
    U1MODEbits.STSEL = 0;               // stop bits bit 0
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline int                              // return 0 if not available
midi_parse(                             // MIDI messages parsing
    int inbyte)                         // byte received from UART
{
static unsigned char note_temp;         // auxiliar note number
static unsigned char midi_state = 0;    // parser automata state
    unsigned char aux_command;          // midi command

    aux_command = inbyte & 0x00F0;      // clear midi channel

    if ((g_butmidi)                     // if not all channels
    && (inbyte & 0x0080)                // and is command
    && ((inbyte & 0x000F) != g_butmidi)) // and is not selected
        return 0;                       // ignore message

    if (aux_command == NOTE_ON)         // midi command parsing
    {   midi_state = 1;                 // first byte processed
        return 0;                       // no message complete
    }
    if (aux_command == NOTE_OFF)        // midi command parsing
    {   midi_state = 4;                 // first byte note off proces
        return 0;                       // no message complete
    }
    if ((midi_state == 1)               // midi note number parsing
    ||  (midi_state == 4))              // for both note on and off
    {   midi_state ++;                  // appoint to next state
        note_temp = inbyte;             // saves note number
        return 0;                       // no message complete
    }
    if (midi_state == 2)                // velocity value parsing
    {   midi_state = 0;                 // reset to initial state
        g_note = note_temp;             // returns note
        g_velo = inbyte;                // velocity value received
    }
    if (midi_state == 5)                // velocity for note off
    {   midi_state = 0;                 // reset to initial state
        g_note = note_temp;             // returns note
        g_velo = 0;                     // for note off assume 0
    }
    return 1;                           // return values available
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// midi.c - functions for MIDI messages received from UART
// version 1.00 - 20070525
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define NOTE_ON     0x0090              // midi command note on
#define NOTE_OFF    0x0080              // midi command note off
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void midi_ini(void);                    // midi initialization
int midi_parse(int inbyte);             // midi parser
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


#ifndef MINMAX_H
#define MINMAX_H
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// nano.c - main program nanosynth
// version 1.01 - 20070611
// version 1.05 - 20070614 - pointed structs to dco and portm
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define FCY 20000000                    // cycle machine frequency
#include "p30f3014.h"
#include "adcon.h"
#include "buttn.h"
#include "dacon.h"
#include "dca.h"
#include "dco.h"
#include "dsply.h"
#include "env.h"
#include "filt.h"
#include "lfo.h"
#include "minmax.h"
#include "midi.h"
#include "pers.h"
#include "portm.h"
#include "timer.h"
#include "freq.c"                       // frequency table
#include "wave.c"                       // wave table
#define defined_in                      // defined here the
#include "glob.h"                       // global variables
#include "logt.c"                       // log table
#include "expt.c"                       // exp table

    _FOSC(CSW_FSCM_OFF & HS2_PLL8)      // 20 MHz Xtal = 20 Mips
    _FWDT(WDT_OFF)                      // watchdog timer off
    _FBORPOR(MCLR_DIS & PBOR_OFF & BORV_45) 
    _FGS(CODE_PROT_OFF)                 // code protection off

extern unsigned int dco_deltph[];
extern int buttn_change;
extern int dco_treshsquare;
extern int env_value_adsr;
extern int env_value_ar;
extern int lfo_value;
void __attribute__((interrupt)) _T1Interrupt(void);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int main(void)
{
    int i, r;

    adcon_ini();                        // AD converters initialize
    buttn_ini();                        // buttons initialization
    dacon_ini();                        // DA converter init
    dsply_ini();                        // display initialization
    midi_ini();                         // midi initialization
    pers_read();                        // read persistent settings
    buttn_show();                       // shows initial selection

    timer_1_ini_i(453);                 // int timer1 init 44052.8 Hz
//    timer_1_ini_i(624);                 // int timer1 init 32000 Hz
//    timer_1_ini_i(799);                 // int timer1 init 25000 Hz

//    timer_2_ini(1999);                  // timer 2 init at 10000 Hz
    timer_2_ini(3999);                  // timer 2 init at 5000 Hz
                                        // load buttons ee status
    dco_set_wave();                     // set waveform

    while (1)
    {
        if (U1STAbits.URXDA)            // if MIDI data byte available
        {
            i = U1RXREG;                // receive message byte
            r = midi_parse(i);          // MIDI parsing
            if (r)                      // if message available
            {   if (g_velo)             // if NOTE ON message
                {
                    dco_calc_ph(g_note);// calc phase for portm
                    portm_set_ph();     // load deltaphase
                    env_adsr_on();      // starts ADSR envelope
                    env_ar_on();        // starts AR envelope
                }
                else
                    env_adsr_off();     // stops ADSR
            }
        }
        if (IFS0bits.T2IF)              // if timer2 triggered
        {
            env_adsr_run();             // runs adsr envelope
            env_ar_run();               // runs ar envelope
            filt_set(env_value_ar);     // set filter frequ and reson
            lfo_run();                  // runs lfo
            portm_run();                // portamento sampling
            dca_set(env_value_adsr);    // REDUNDANT ...!

            if (g_butmodn == MODFRQ)    // frequence modulation
            {                           // updates delta phase
                dco_deltph[0] += lfo_value << 2; // upd
                dco_deltph[1] += lfo_value << 2; // upd
            }

            (g_butmodn == MODAMP)       // amplitude modulation
                ? dca_set(env_value_adsr 
                    + (lfo_value >> 1))
                : dca_set(env_value_adsr);

            if (g_butmodn == MODWID)    // pulse width from lfo
                dco_treshsquare = (lfo_value << 6) + g_sqwide;
            else
            if (g_butmodn == MODWAR)    // pulse width from ar
                dco_treshsquare = (env_value_ar << 5) + g_sqwide;
            else
                dco_treshsquare = g_sqwide;

            IFS0bits.T2IF = 0;          // reset interruption flag
        }

        buttn_run();                    // buttons scan

        r = adcon_read();               // if analog data available
        if (r)
        {
            lfo_set();                  // set values for lfo
            env_ar_set();               // set ars values
            env_adsr_set();             // set adsr values
            portm_set_tm();             // loads portamento value
            if (g_buttune == TNHALFT)   // set halftone tune value
            {
                dco_calc_ph(g_note);    // calc phase for portm
                portm_set_ph();         // load deltaphase
            }
            if (g_buttune == TNPITCH)   // set pitch in fractions
            {
                dco_calc_ph(g_note);    // calc phase for portm
                portm_set_ph();         // load deltaphase
            }
        }

        if (buttn_change)               // buttons events
        {   buttn_change = 0;
            pers_write();               // write persistent settings
            dco_set_wave();             // set waveform
        }
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void)
{
    dco_run();                          // dco procedure
    filt_run();                         // filter procedure
    dca_run();                          // dca - adsr running
/*
    g_sample = min(g_sample, 2047);     // saturation hi
    g_sample = max(g_sample, -2047);    // saturation lo
*/
    dacon_write();                      // write output sample

    IFS0bits.T1IF = 0;                  // reset timer 1 interrupt flag
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// pers.c - persistence in eeprom
// version 1.02 - 20070611 - optimizing buttons debounce
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// Copyright (C) 2007 miguel angel labolida
// This program is under the terms of the GNU General Public License
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "DataEE.h"
#include "buttn.h"
#include "dsply.h"
#define defined_in extern
#include "glob.h"

int _EEDATA(32) buttn_ee[16] =         // eeprom save area
    {0, 0, 1, 0, 0, 2000, 2000, 2000, 2100, 0, 0, 0, 0, 0, 0, 0}; 
//   0  1  2  3  4  5     6     7     8     9  A  B  C  D  E  F
static int pers_save[16];              // ram shadow eeprom
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void pers_read(void)                    // read from eeprom
{
	ReadEE(                             // EEPROM loading in ram
        __builtin_tblpage(buttn_ee), 
        __builtin_tbloffset(buttn_ee), 
        pers_save, ROW);  
    g_butwave = pers_save[0];
    g_butmodn = pers_save[1];
    g_butdco2 = pers_save[2];
    g_butmidi = pers_save[3];
    g_buttune = pers_save[4]; 
    g_o1half = pers_save[5];            // p1 dco1 halftone tune
    g_o1ptch = pers_save[6];            // p1 dco1 pitch tune
    g_o2half = pers_save[7];            // p2 dco2 halftone tune
    g_o2ptch = pers_save[8];            // p2 dco2 pitch tune
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void pers_write(void)                   // write values in eeprom
{
    pers_save[0] = g_butwave;
    pers_save[1] = g_butmodn;
    pers_save[2] = g_butdco2;
    pers_save[3] = g_butmidi;
    pers_save[4] = g_buttune;
    pers_save[5] = g_o1half;            // p1 dco1 halftone tune
    pers_save[6] = g_o1ptch;            // p1 dco1 pitch tune
    pers_save[7] = g_o2half;            // p2 dco2 halftone tune
    pers_save[8] = g_o2ptch;            // p2 dco2 pitch tune
    EraseEE(                            // erase values in eeprom
        __builtin_tblpage(buttn_ee),
        __builtin_tbloffset(buttn_ee), ROW); 
    WriteEE(pers_save,                  // write values in eeprom
        __builtin_tblpage(buttn_ee),    
        __builtin_tbloffset(buttn_ee), ROW); 
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// pers.h - persistence in eeprom
// version 1.02 - 20070611 - optimizing buttons debounce
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// Copyright (C) 2007 miguel angel labolida
// This program is under the terms of the GNU General Public License
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void pers_read(void);                   // buttons initialization
void pers_write(void);                   // write values in eeprom
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// portm.c - portamento sampled at 10KHz
// version 1.00 - 20070603
// version 1.05 - 20070614 - pointed structs to dco and portm
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include "p30f3014.h"
#include "portm.h"
#define defined_in extern               // defined externally
#include "glob.h"                       // global variables
extern int logvalue[];
extern unsigned int dco_deltph[];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int portm_phinc[2];              // phase increment
static int portm_time = 0;              // portamento time
// public:
int portm_phnew[2];                     // new delta phase
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void portm_run(void)             // portamento sampling
{
static unsigned int timer = 1;
    if (! portm_time) return;           // no portamento
    timer --;                           // prescaler
    if (timer) return;
    timer = portm_time;                 // reloads timer
    if ((dco_deltph[0] == portm_phnew[0]) 
    &&  (dco_deltph[1] == portm_phnew[1])) 
        return;

    dco_deltph[0] += portm_phinc[0];
    if (portm_phinc[0] > 0)
    {   if (dco_deltph[0] > portm_phnew[0])
            dco_deltph[0] = portm_phnew[0];
    }
    else
    {   if (dco_deltph[0] < portm_phnew[0])
            dco_deltph[0] = portm_phnew[0];
    }

    dco_deltph[1] += portm_phinc[1];
    if (portm_phinc[1] > 0)
    {   if (dco_deltph[1] > portm_phnew[1])
            dco_deltph[1] = portm_phnew[1];
    }
    else
    {   if (dco_deltph[1] < portm_phnew[1])
            dco_deltph[1] = portm_phnew[1];
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void portm_set_ph(void)          // set actual midi note phase
{
    portm_phinc[0] = (int)(portm_phnew[0] - dco_deltph[0]) / 20;
    if (! portm_phinc[0]) 
        portm_phinc[0] = 1; // prevents zero increment

    portm_phinc[1] = (int)(portm_phnew[1] - dco_deltph[1]) / 20;
    if (! portm_phinc[1])
        portm_phinc[1] = 1; // prevents zero increment
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void portm_set_tm(void)                 // set portamento time
{
//    portm_time = time >> 4;             // loads time value (slow)
    portm_time = g_portam >> 5;         // loads time value
    if (! portm_time)                   // if no portamento
    {   dco_deltph[0] = portm_phnew[0]; // set imediately new value    
        dco_deltph[1] = portm_phnew[1]; // set imediately new value
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// portm.h - portamento sampled at 10KHz
// version 1.00 - 20070603
// version 1.05 - 20070614 - pointed structs to dco and portm
// version 1.06 - 20070614 - dual dco and portm
// version 1.07 - 20070615 - clear overrun - optimizing
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void portm_run(void);                   // portamento sampling
void portm_set_ph(void);                // set actual midi note phase
void portm_set_tm(void);                // set portamento time
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// timer.c - timers functions of initialization
// version 1.00 - 20070525
// version 1.07 - 20070615 - clear overrun - optimizing
// T(measured) = (PRx + 1) * FCY * TMRx prescale =
// 4000 * (1/20000000) * 1 = 200 us   F =  5000.0 Hz 
// 2000 * (1/20000000) * 1 = 100 us   F = 10000.0 Hz
// 1024 * (1/20000000) * 1 = 51.2 us  F = 19531.3 Hz
// 1000 * (1/20000000) * 1 = 50.0 us  F = 20000.0 Hz
// 800 * (1/20000000) * 1 =  40.0 us  F = 25000.0 Hz
// 625 * (1/20000000) * 1 =  31.3 us  F = 32000.0 Hz
// 512 * (1/20000000) * 1 =  25.6 us  F = 39062.5 Hz
// 455 * (1/20000000) * 1 = 22.75 us  F = 43956.0 Hz
// 454 * (1/20000000) * 1 = 22.70 us  F = 44052.8 Hz
// 400 * (1/20000000) * 1 = 20.00 us  F = 50000.0 Hz
// 256 * (1/20000000) * 1 = 12.80 us  F = 78125.0 Hz
// 213 * (1/20000000) * 1 = 10.65 us  F = 93896.7 Hz
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define FCY 20000000                    // cycle machine frequency
#include "p30f3014.h"
#include "timer.h"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void timer_1_ini_i(int period)          // int timer 1 initialization
{
    T1CONbits.TON = 0;                  // timer on control 0=stop
    T1CONbits.TCKPS = 0;                // input clock prescale 0=1:1
    T1CONbits.TCS = 0;                  // timer ck src 0=internal(fosc/4)
    PR1 = period;                       // period register
    IPC0bits.T1IP = 7;                  // int. priority 7 (highest) 
    IEC0bits.T1IE = 1;                  // timer 1 interrupt enable
    T1CONbits.TON = 1;                  // timer on control 1=start
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void timer_2_ini(int period)            // timer 2 initialization
{
    T2CONbits.TON = 0;                  // timer on control 0=stop
    T2CONbits.TCKPS = 0;                // input clock prescale 0=1:1
    T2CONbits.TCS = 0;                  // timer ck src 0=internal(fosc/4)
    PR2 = period;                       // period register
    IPC1bits.T2IP = 3;                  // int. priority 3 (medium) 
    IEC0bits.T2IE = 0;                  // timer 2 interrupt disable
    T2CONbits.TON = 1;                  // timer on control 1=start
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void timer_2_ini_i(int period)          // int timer 2 initialization
{
    timer_2_ini(period);
    T2CONbits.TON = 0;                  // timer on control 0=stop
    IEC0bits.T2IE = 1;                  // timer 2 interrupt enable
    T2CONbits.TON = 1;                  // timer on control 1=start
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// timer.h - timers initialization functions
// version 1.00 - 20070525
// version 1.07 - 20070615 - clear overrun - optimizing
// T(measured) = (PRx + 1) * FCY * TMRx prescale =
// 4000 * (1/20000000) * 1 = 200 us   F =  5000.0 Hz 
// 2000 * (1/20000000) * 1 = 100 us   F = 10000.0 Hz
// 1024 * (1/20000000) * 1 = 51.2 us  F = 19531.3 Hz
// 1000 * (1/20000000) * 1 = 50.0 us  F = 20000.0 Hz
// 800 * (1/20000000) * 1 =  40.0 us  F = 25000.0 Hz
// 625 * (1/20000000) * 1 =  31.3 us  F = 32000.0 Hz
// 512 * (1/20000000) * 1 =  25.6 us  F = 39062.5 Hz
// 455 * (1/20000000) * 1 = 22.75 us  F = 43956.0 Hz
// 454 * (1/20000000) * 1 = 22.70 us  F = 44052.8 Hz
// 400 * (1/20000000) * 1 = 20.00 us  F = 50000.0 Hz
// 256 * (1/20000000) * 1 = 12.80 us  F = 78125.0 Hz
// 213 * (1/20000000) * 1 = 10.65 us  F = 93896.7 Hz
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void timer_1_ini_i(int period);         // int timer 1 initialization
void timer_2_ini(int period);           // timer 2 initialization
void timer_2_ini_i(int period);         // int timer 2 initialization
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


//  wave table generator wavgn.cpp - ver.1.05 - 20070609
// Copyright (C) 2007  miguel angel labolida
// This program is under the terms of the GNU General Public License
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//          output file name with extension: wave.c
//                       resolution in bits: 14
//                         samples quantity: 16
//                            resol.max.val: 16384
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     int sinewave[16] = {
        0x0000, 0x0C3E, 0x16A0, 0x1D90, 0x1FFF, 0x1D90, 0x16A0, 0x0C3E, 
        0x0000, 0xF3C1, 0xE95F, 0xE26F, 0xE000, 0xE26F, 0xE95F, 0xF3C1, 
        };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     int sawtooth[16] = {
        0xE000, 0xE400, 0xE800, 0xEC00, 0xF000, 0xF400, 0xF800, 0xFC00, 
        0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, 
        };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     int triangular[16] = {
        0xE000, 0xE7FF, 0xEFFF, 0xF7FF, 0xFFFF, 0x07FF, 0x0FFF, 0x17FF, 
        0x1FFF, 0x17FF, 0x0FFF, 0x07FF, 0xFFFF, 0xF7FF, 0xEFFF, 0xE7FF, 
        };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -