PCM Digital Synthesizer

Dependencies:   LCD mbed

/media/uploads/p_igmon/img_1731-w480.jpg

Synthsizer.cpp

Committer:
p_igmon
Date:
2016-09-02
Revision:
0:ad6637c36dc7

File content as of revision 0:ad6637c36dc7:

/**********************************************************************


***********************************************************************/

#include "synthesizer.h"

#ifdef DCF
__asm   S16 dcf64(S32 *param ,S32 *signal){

    PUSH    {R4-R7}
    LDR    r2,[r0 , #0]; param a0
    LDR    r3,[r1 , #0]; signal 0
    SMULL   r4,r5,r2,r3

    LDR    r6,[r0 , #4]; a1
    LDR    r7,[r1 , #4]; x1
    SMLAL  r4,r5,r6,r7; Top r5 Bottom r4
    LDR    r2,[r0 , #8]; b0
    LDR    r3,[r1 , #8]; x2
    SMLAL  r4,r5,r2,r3
    LDR    r6,[r0 , #12]; b1
    LDR    r7,[r1 , #12]; y1
    SMLAL  r4,r5,r6,r7
    LDR    r2,[r0 , #16]; b2
    LDR    r3,[r1 , #16]; y2
    SMLAL  r4,r5,r2,r3
    
    MOV     r0,r1; r0 = r1 signal
    ADDS    r4 ,r4, r4 ; add the least significant words
    ADCS    r5 ,r5, r5 ; add the most significant words with carry
    ADDS    r4, r4, r4 ; add the least significant words
    ADCS    r5, r5, r5 ; add the most significant words with carry

    LDR     r6,[r1, #12]; dcf_y1
    LDR     r3,[r0, #4]; dcf_x1
    STR     r6,[r1, #16]; dcf_y2 = dcf_y1
    STR     r3,[r0, #8]; dcf_x2 = dcf_x1
    LDR     r4,[r1, #0]; sample
    STR     r5,[r0, #12]; dcf_y1 = result
    STR     r4,[r1 ,#4]; dcf_x1 = sample

    ASR     r0,r5,#16; r0 = r5 >>16
    POP    {R4-R7}
    BX      LR
;    ENDP
            
    ALIGN
;    END
}
#endif

__asm S16 satAdd16(S16 val1 ,S16 val2){
    QADD16    r0,r0,r1
    
    BX      LR
;    ENDP
            
    ALIGN
;    END
}

__asm S32 satAdd32(S32 val1 ,S32 val2){
    QADD    r0,r0,r1
    
    BX      LR
    ENDP
            
    ALIGN
    END
}

int gen_encount;

extern DigitalOut generating;
#define GENERATE_ON generating=1;
#define GENERATE_OFF generating=0;

S16 limit;

/* DMA WAVE BUFFER */
extern S16 DMA_Buffer[];
extern __IO BUFFER_StateTypeDef BufferOffset;

extern U8 midi_base_ch ;
volatile U8 midi_note_ch ;
volatile U8 midi_prog_ch ;

volatile U8 samplecount = 0; 
extern  S8 MasterTune;// -128 - +127
volatile int portament;
S16 MasterVolume = 127<<8;// max 127<<8
volatile S16 mvoldiv = 0;

extern STR_VOICE voice[];

//static _UWORD df_table[] ={24883,26363,27930,29591,31351,33215,35190,37282,39499,41848,44336,46973};// 44.1k 440Hz@A4 1404029
static U16 df_table[] ={24996,26482,28057,29725,31493,33366,35350,37452,39679,42038,44538,47186};// 44.1k 442Hz@A4

static U16 k[16] ={65535,61439,57343,53247,49151,45055,40959,36863,32767,28671,24575,20479,16383,12287,8191,4095};// 121009

#ifdef REVERVE16BIT
S16 reverve_buf[22000];
S16 *reverve_wtemp;
#else
S8 reverve_buf[44000];
S8 *reverve_wtemp;
#endif

extern volatile int TimerCount10mS ;
extern volatile int KeyValDiv;

extern GENERATOR sgen[];
extern GENERATOR dgen[];
extern GENERATOR_TEMP dgen_temp[];
extern GENERATOR *gen ;// = &sgen[(PresetVoiceNum - 1)*PRGGENMAX] set by Menu PresetVoice
extern GENERATOR *pgen;// = &dgen[0]; 
extern GENERATOR_TEMP *pgen_temp;//  = &dgen_temp[0]; 
extern WaveDef Wave[];

extern U8 PresetVoiceNum;
extern U8 MidiChannel;;
extern S8 MasterTune;;
extern int rch_pol;

void init_voice(void){
#ifdef DCF
    int i;
    GENERATOR *gena;
    GENERATOR_TEMP *gena_temp;
    STR_VOICE *voicea;
    gena = pgen;
    gena_temp = pgen_temp;
    voicea = &voice[0]; 
    for (i=0;i<VOICEMAX;i++){
            voicea->enable = 0;
            voicea->signal[0] = voicea->signal[1] = voicea->signal[2] = voicea->signal[3] = voicea->signal[4] = voicea->signal[5] = 0;
            voicea->gen = gena;
            voicea->gen_temp = gena_temp;
            gena += PRGGENMAX;
            gena_temp += PRGGENMAX;
            voicea++;
    }
#endif
}

void gen_attack(GENERATOR *gena,GENERATOR_TEMP *gena_temp){
    /* Generator Start */
    gena_temp->lfo1value = 0;
    gena_temp->lfo1count = 0;
    gena_temp->lfo2count = 0;
    gena_temp->lfo1delaycount = gena->lfo1delaytime;
    gena_temp->lfo2delaycount = gena->lfo2delaytime;
    gena_temp->x = 0;
    gena_temp->startadr = (U8 *)Wave[gena->wave_num - 1].startaddr;
    gena_temp->p1 = (U8 *)Wave[gena->wave_num - 1].p1;
    gena_temp->p2 = (U8 *)Wave[gena->wave_num - 1].p2;
    gena_temp->cycle = (U8 *)Wave[gena->wave_num - 1].cycle;
    gena_temp->samplecountp1p2 = (U8 *)((uint8_t *)gena_temp->p2 - (uint8_t *)gena_temp->p1);    
    gena_temp->voltemp = 0;
    gena_temp->voltemp1 = (gena->volume<<16) / gena->attacktime;
    gena_temp->voltemp2 = ((gena->volume * gena->sustainlevel) /100) <<16;
                                        
    gena_temp->status = GEN_NOTEON;
    gena_temp->eg_status = EG_IDLE;
}

void init_sgen(void){
    GENERATOR gena ={
        1,// U8 sw;// 0,1
        1,// U8 wave_num;// 1-128
        0,// S8 notebias;// -128 - +127
        31,// U8 pan;// 0-31
        0,// S16 detune;// -512 - +511
        32512,// U16 volume;// 0-127<<8
        1,// U16 attacktime;//
        100,// U16 decaytime;//
        80,// U8 sustainlevel;//
        0,// U16 releasetime;// 0-21
        0,// U16 lfo1depth;
        0,// U8 lfo1speed;
        0,// U8 lfo1type;
        0,// U16 lfo1delaytime;// 0-3000
        0,// U16 lfo2depth;
        0,// U8 lfo2speed;
        0,// U8 lfo2type;
        0,// U16 lfo2delaytime;// 0-3000
    };  

//    for(int i=0;i<PRGGENMAX*128;i++){
    for(int i=0;i<PRGGENMAX*64;i++){
        memcpy (&sgen[i],&gena,sizeof(GENERATOR));
    }
}


void notenum2df(GENERATOR *gen ,GENERATOR_TEMP *gen_temp){
    U32 temp;
    U8 octave ,notenum;
    notenum = gen_temp->notenum + gen->notebias;
    octave = notenum / 12;
    /* Pitch Adjuster */

    if (gen_temp->cycle == 0){
        temp = df_table[(notenum % 12)] * (U32)((U8 *)gen_temp->samplecountp1p2);// 2^16 * 2^(7-8)
    }else{
        temp = df_table[(notenum % 12)] * (U32)((U8 *)gen_temp->cycle);
    }
//    temp += ((S32)(temp * MasterTune))>>12;// +32 縺ァ +1% ・・128 縺ァ +4%
//    temp += ((S32)(temp * MasterTune))>>4;// +32 縺ァ +1% ・・128 縺ァ +4%
    gen_temp->df = (temp << (1 + octave));
//    gen_temp->df += (S32)((S32)((gen_temp->df>>19) * MasterTune)>>8);// 140617
    gen_temp->df += (S32)((S32)((gen_temp->df>>8) * MasterTune)>>4);// 140618
}

void noteon(U8 notenum ,U8 velocity){
    U8 i;
    U8 gencount ,sgencount;
    STR_VOICE *voicea;
    GENERATOR *sgen;
    GENERATOR *gena;
    GENERATOR_TEMP *gena_temp;
    voicea = &voice[0];
    sgen = gen;// source
    gena = pgen;// 螳滉ス薙・縺サ縺・〒
    gena_temp = pgen_temp;// 螳滉ス薙・縺サ縺・〒
    gencount = sgencount = 0;


    if (portament){
        while(sgencount < PRGGENMAX){// 騾壼クク・・
            if(sgen->sw){ // 130302
                while(gencount < GENMAX){
                        if(gena_temp->status == GEN_POROFF){
                            gena_temp->status = GEN_PORON;
                            gena_temp->notenum = notenum;
                            notenum2df(gena,gena_temp);
//                          gena->velocity = velocity;
                            gena++;
                            gena_temp++;
                            gencount++;
                            break;// exit while
                        }
                    gena++;
                    gena_temp++;
                    gencount++;
                }
            }
            sgen++;
            sgencount++;
        } // while loop
    }else{
#ifdef DCF
        if(gen_encount > (GENMAX - 1))return;// 140707 Gen count limit
        for (i=0;i<VOICEMAX;i++){
            if(voicea->enable == 0) break;// 遨コ縺・※縺・kvoice
            voicea++;
        }
        if(i>(VOICEMAX - 1))return;// All Voice is Working
//        voicea->enable = 0;
        gena = voicea->gen;
        gena_temp = voicea->gen_temp;
        sgen = gen;// source

        for (i=0;i<PRGGENMAX;i++){
            if(sgen->sw){
                memcpy(gena ,sgen ,sizeof(GENERATOR));// sgen1 ->> gena1
                gena_temp->notenum = notenum;
                gena_temp->velocity = velocity;
                gen_attack(gena ,gena_temp);
                notenum2df(gena ,gena_temp);
                gen_encount++;// 140707
                voicea->enable |= 1<<i;
            }else{
                gena_temp->status = GEN_IDLE;
                gena->sw = 0;
                gena_temp->voltemp = 0;
            }
            gena++;
            gena_temp++;
            sgen++; 
        }

    }
#else
        if(gen_encount > (GENMAX - 1))return;// 140707 Gen count limit
        while(sgencount < PRGGENMAX){// 騾壼クク・・
            if(sgen->sw){ // 130302
                while(gencount < GENMAX){
                    if(gena_temp->status == GEN_IDLE){
                        memcpy(gena ,sgen ,sizeof(GENERATOR));// sgen ->> gena
                        gena_temp->notenum = notenum;
                        gena_temp->velocity = velocity;
                        gen_attack(gena ,gena_temp);
                        notenum2df(gena ,gena_temp);
                        gena++;
                        gena_temp++;
                        gencount++;
                        gen_encount++;// 140707
                        break;// exit while
                    }
                    gena++;
                    gena_temp++;
                    gencount++;
                }
            }
            sgen++;
            sgencount++;
        }
    }
#endif   
}

void noteoff(U8 notenum ,U8 velocity){
    U8 i;
    GENERATOR *gena;
    GENERATOR_TEMP *gena_temp;
    gena = pgen;// 螳滉ス薙・縺サ縺・〒
    gena_temp = pgen_temp;// 螳滉ス薙・縺サ縺・〒
    for(i=0;i<GENMAX;i++){
        if(((gena_temp->status == GEN_NOTEON)||(gena_temp->status == GEN_PORON)) && (gena_temp->notenum == notenum)){ // 130302

/*  111025 Velocity active untill release time
            gena->velocity = 0;
*/
            if (portament){
                gena_temp->status = GEN_POROFF;
            }else{
                /* Generator Start Release  */
                gena_temp->status = GEN_NOTEOFF;
                gena_temp->eg_status = EG_RELEASE;
            }
        }
        gena++;
        gena_temp++;
    }
}

void pgmchg(U8 number){
    if (number >63) return;
    PresetVoiceNum = number + 1;
    presetvoice();
}


/*
    Interpolaton value
    x - 逵溘・豕「蠖「縺ョ蠎ァ讓・
    y - 陬憺俣險育ョ励↓繧医▲縺ヲ蠕励ky(x)
        
    謖・焚驛ィ・主ー乗焚驛ィ
      20      12   bit
*/

 uint32_t temp32a;
/* DMA Wave繝舌ャ繝輔ぃ縺ォ豕「蠖「繧呈嶌縺崎セシ繧€ */
void wave_generate(void){
    U8 i;
    U16 count;
    S32 rch,lch;
    S16 rchout,lchout;
    S16 temps16;
    S32 sample;
    S16 interpovalue;
    S32 interpovalue32;
    GENERATOR *gena;
    GENERATOR_TEMP *gena_temp;
    STR_VOICE *voicea;
    
    volatile S16 *ptr;
    U16 temp;
    S32 y;
    U32 expo_x; // 謖・焚驛ィ 20bit
    U16 fract_x;// 蟆乗焚驛ィ 12bit

    volatile S16 *ptr0;
  GENERATE_ON
    if (--TimerCount10mS  < 0) TimerCount10mS  = 0;

    if (BufferOffset == DMA_FullComplete){
        ptr0 = (S16 *)&DMA_Buffer[DMA_BUFFERSIZE>>1];// From Half
    }else{
        ptr0 = (S16 *)&DMA_Buffer[0];// From Top
    }    
    BufferOffset = DMA_Idle;

    count = DMA_BUFFERSIZE/4;// DMA 繝舌ャ繝輔ぃ縺ョ繧オ繧、繧コ
    while(count-- > 0){
        if(samplecount++ > 43){
            samplecount = 0;
            envelope_work();
        }
        voicea = &voice[0]; 
        sample = 0;
        gena = pgen;// 螳滉ス薙・縺サ縺・〒
        gena_temp = pgen_temp;// 螳滉ス薙・縺サ縺・〒
        for(i=0;i<GENMAX;i++){
            if(gena_temp->eg_status != EG_IDLE){
            // if(gena_temp->status !=GEN_IDLE){

/*
#ifdef BEND
                gena->x += (((U32)gena_temp->df>>16) + (S16)gena->detune + gena->lfo1value + gena->bendvalue);
#else
//                gena_temp->x += (((U32)gena_temp->df>>16) + (S16)gena->detune + gena_temp->lfo1value);
                gena_temp->x += (((U32)gena_temp->df>>16) + (S32)gena->detune + gena_temp->lfo1value);
#endif
*/
                gena_temp->x += gena_temp->xx;

                if (gena_temp->x <= (U32)gena_temp->p2<<12){
                    goto generate1;
                }else if(gena_temp->p1 == 0){// No Loop
                    goto nothing;
                }else{
                    gena_temp->x -= ((U32)gena_temp->samplecountp1p2 <<12);// Loop p1 - p2
                }
                
generate1:      expo_x = gena_temp->x>>12;
#ifdef INTERPO2
                temp = (gena_temp->x) & 0xfff;
                ptr = (S16*)gena_temp->startadr +((U32)expo_x);
                y  = (*ptr * (4096 - temp));
                ptr++;
                y  += *ptr * temp;
                interpovalue32 = (S32)((S16)(y>>12) * limit)>>3;
#else
                fract_x = (gena_temp->x>>8) & 0x0f;
                ptr = (S16*)gena_temp->startadr +((U32)expo_x);

                temp = k[fract_x];
                y  = *ptr * temp;
                ptr++;
                y  += (*ptr * (65535 - temp));
                interpovalue32 = (S16)(y>>16) * limit;
                
#endif

#ifdef DIST
//            if (gena_temp->eg_status < EG_RELEASE){
                if (interpovalue32 > 120<<8){
                    interpovalue32 = 120<<8;
                }else if(interpovalue32 < (120<<8) * -1){
                    interpovalue32 = (120<<8) * -1;
                }
//            }
#endif

#ifdef 0
            if (gena_temp->eg_status < EG_RELEASE){
                if (interpovalue > limit<<8){
                    interpovalue = limit<<8;
                }else if(interpovalue < (limit<<8) * -1){
                    interpovalue = (limit<<8) * -1;
                }
            }
#endif

//                sample += ((S16)interpovalue * ((gena_temp->voltempL)>>1));// 譛牙柑譯∵焚32繝薙ャ繝・
                sample = satAdd32(sample ,((S16)interpovalue32 * ((gena_temp->voltempL)>>1)));
nothing:

            }
#ifdef DCF
            if ((i & (PRGGENMAX - 1))== (PRGGENMAX - 1)){
                voicea->signal[0] = (S32)(sample);// 譛牙柑譯∵焚32繝薙ャ繝・
                voicea++;
                sample = 0;
            }
#endif
            gena++;
            gena_temp++;
        }
#ifdef DCF
        voicea =&voice[0];
        lch = 0;
        i = VOICEMAX;
        while(i--){
//            lch += (S16)(dcf64(voicea->dcf_param ,&voicea->signal[0]));
            lch = satAdd16(lch ,(S16)(dcf64(voicea->dcf_param ,&voicea->signal[0])));
//            lch += (S16)((S32)voicea->signal[0]>>16);// NoneLPF
            voicea++;
        }
#else
        lch = sample >> 16;
#endif

//       temps16 = (((S32)lch) * (((S16)MasterVolume)<<1))>>16;
 
#ifdef 0
        if (lch > limit<<8){
            lch = limit<<8;
        }else if(lch < (limit<<8) * -1){
            lch = (limit<<8) * -1;
        }    
#endif 
       
#if 0
         /* Reverve */
#ifdef REVERVE16BIT 
        if (count & 1){
            if(++reverve_wtemp == (reverve_buf + 22000)) reverve_wtemp = reverve_buf;
            *reverve_wtemp = temps16;
            rchout = lchout = 0;
            for(i=0;i<90;i += 3){
                S16 *temp_ptr = reverve_wtemp - reverve_tap[i];
                if(temp_ptr < reverve_buf){
                    lchout += ((S16)(*(temp_ptr + 22000)) * (U16)reverve_tap[i+1])>>18;
                    rchout += ((S16)(*(temp_ptr + 22000)) * (U16)reverve_tap[i+2])>>18;
                }else{
                    lchout += ((S16)(*temp_ptr) * (U16)reverve_tap[i+1])>>18;   
                    rchout += ((S16)(*temp_ptr) * (U16)reverve_tap[i+2])>>18;   
                }
            }
        }
#else
        /* Reverve */
        rchout = lchout = 0;
        if(++reverve_wtemp == (reverve_buf + 44000)) reverve_wtemp = reverve_buf;
        *reverve_wtemp = S8(temps16>>8);
        for(i=0;i<90;i += 3){
            S8 *temp_ptr = reverve_wtemp - reverve_tap[i];
            if(temp_ptr < reverve_buf){
                lchout += ((S8)(*(temp_ptr + 44000)) * (U16)reverve_tap[i+1])>>10;
                rchout += ((S8)(*(temp_ptr + 44000)) * (U16)reverve_tap[i+2])>>10;
            }else{
                lchout += ((S8)(*temp_ptr) * (U16)reverve_tap[i+1])>>10;    
                rchout += ((S8)(*temp_ptr) * (U16)reverve_tap[i+2])>>10;    
            }
        
        }

#endif        
//        *bufptr++ = ((rch + (rchout & 0xffff))<<16)|(((lch & 0xffff) + (lchout & 0xffff)) & 0xffff);

       *ptr0++ = temps16 + rchout;
       *ptr0++ = temps16 + lchout;
#endif

        temps16 = (((S32)lch) * (((S16)MasterVolume)<<1))>>16;
        *ptr0++ = temps16;
        *ptr0++ = rch_pol * temps16;

     }
  GENERATE_OFF
}


void uGen4_init(void)
{
    GENERATOR *gena;
    GENERATOR_TEMP *gena_temp;

    mvoldiv = 0;
    portament = 0;// 130213

    gena = pgen;
    gena_temp = pgen_temp;
    for(int i=0;i<GENMAX;i++){
        gena_temp->status = GEN_IDLE;
        gena->sw = 0;
        gena_temp->voltemp = 0;
        gena++;
        gena_temp++;
    }       

    init_voice();

    midi_note_ch = midi_base_ch;
    midi_prog_ch = midi_base_ch;

//    init_midi();

}