Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Jan Ostman
Published

The dsp-Gplug MIDI Synth

The worlds smallest Analog Modeling MIDI synth.

Full instructions provided3,573
The dsp-Gplug MIDI Synth

Story

Read more

Code

file_6831.txt

C/C++
//**************************************************************************/
//    Analog Modeling Synth main code
//    Copyright DSP Synthesizers (c) 2014
//    Code may not be redistributed and is for personal use only
//    The code may only be listed here on Hackster.io
//
//**************************************************************************/

#include "wiring.h"

#include "LPC8xx.h"

#include "sct_fsm.h"

//#include "TFT.h"





/* Control register bit definition. */

#define MRT_INT_ENA          (0x1<<0)

#define MRT_REPEATED_MODE    (0x00<<1)

#define MRT_ONE_SHOT_INT     (0x01<<1)

#define MRT_ONE_SHOT_STALL   (0x02<<1)



/* Status register bit definition */

#define MRT_STAT_IRQ_FLAG    (0x1<<0)

#define MRT_STAT_RUN         (0x1<<1)



#define SPI_CFG_ENABLE (0x1)

#define SPI_CFG_MASTER (0x4)

#define SPI_STAT_RXRDY (0x1)

#define SPI_STAT_TXRDY (0x2)

#define SPI_STAT_SSD (0x20)

#define SPI_STAT_MSTIDLE (0x100)

#define SPI_TXDATCTL_SSEL_N(s) ((s) << 16)

#define SPI_TXDATCTL_EOT (1 << 20)

#define SPI_TXDATCTL_EOF (1 << 21)

#define SPI_TXDATCTL_RXIGNORE (1 << 22)

#define SPI_TXDATCTL_FLEN(l) ((l) << 24)



//-------- Synth parameters --------------

uint32_t FREQ[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //OSC pitches

volatile int32_t CUTOFF=65535;     //freq 0-65535

volatile int32_t CFREQ=65535;      //freq 0-65535

volatile int32_t RESONANCE=0;      //reso=0-65535

volatile uint8_t TRIG=1;           //MIDItrig 1=note ON

volatile uint32_t ATTACK0=0xFFFF;  //Attackrate in 30mS steps

volatile uint32_t DECAY0=98;       //Decayrate in 30mS steps

volatile int32_t SUSTAIN0=0xFFFF;  //Sustainlevel 0-65535

volatile uint32_t RELEASE0=0x0;    //Releaserate in 30mS steps

volatile uint32_t ATTACK1=98;	   //Attackrate in 30mS steps

volatile uint32_t DECAY1=98;       //Decayrate in 30mS steps

volatile int32_t SUSTAIN1=0xFFFF;  //Sustainlevel 0-65535

volatile uint32_t RELEASE1=0;      //Releaserate in 30mS steps

volatile uint32_t DETUNE=1;		   //Osc spread or detune

volatile uint32_t RANGE=64;		   //Osc range

volatile uint8_t ENVMOD=0;		   //Filter ENVMOD

volatile uint8_t LFOMOD=0;		   //Filter LFOMOD

volatile uint8_t WAVEFORM=255;	   //OSC Waveform

volatile uint8_t WRAP=0;		   //OSC Wrap

volatile uint8_t LFORATE=0;		   //LFO frequency

volatile uint8_t LFOWAVE=0;		   //LFO waveform

volatile int32_t MASTERVOL=65535;  //Master volume

volatile uint8_t CHORUSRATE=0;     //Chorus rate

volatile uint8_t CHORUSMOD=0;      //Chorus modlevel

volatile int32_t CHORUSMIX;        //Chorus mix level

volatile int32_t CHORUSFB;         //Chorus feedback level

//-----------------------------------------





volatile uint16_t DACL=1;

volatile uint16_t DACR=1;

uint32_t DCOPH[15];



volatile uint8_t state0=0;    //needs to be reset on a new trig

volatile uint8_t state1=0;    //needs to be reset on a new trig

volatile int32_t volume0=0;

volatile int32_t volume1=0;

volatile uint16_t envstat=1;  //needs to be reset on a new trig



int32_t t[9];



int32_t vi;

int32_t vo;



int16_t DCO;

int16_t DCF;

int32_t ENV;



uint8_t lfocounter=0;

uint32_t next = 1;

volatile uint8_t shrandom;

uint8_t chrcounter=0;

uint8_t pwmcounter=0;



int8_t waveform[256];

const uint32_t NOTES[12]={208065>>2,220472>>2,233516>>2,247514>>2,262149>>2,277738>>2,294281>>2,311779>>2,330390>>2,349956>>2,370794>>2,392746>>2};



volatile uint8_t MIDISTATE=0;

volatile uint8_t MIDIRUNNINGSTATUS=0;

volatile uint8_t MIDINOTE;

volatile uint8_t MIDIVEL;

uint8_t OSCNOTES[5];

const uint16_t ENVRATES[32] = {65535,61540,57544,53548,49552,45556,41560,37564,33568,29572,25576,21580,17584,13588,9592,5596,1600,1503,1407,1311,1215,1119,1022,926,830,734,638,541,445,349,253,157 };



volatile uint16_t writeptr = 0;

volatile uint16_t delayL = 0;

volatile uint16_t delayR = 1023;

volatile int16_t leftCH;

volatile int16_t rightCH;

volatile int32_t chmixL;

volatile int32_t chmixR;







//---------------- Get the base frequency for the MIDI note ---------------

uint32_t MIDI2FREQ(uint8_t note) {

  uint8_t key=note%12;

  if (note<36) return (NOTES[key]>>(1+(35-note)/12));

  if (note>47) return (NOTES[key]<<((note-36)/12));

  return NOTES[key];

}

//-------------------------------------------------------------------------



void MRT_IRQHandler(void) {

  if ( LPC_MRT->Channel[0].STAT & MRT_STAT_IRQ_FLAG ) {

    LPC_MRT->Channel[0].STAT = MRT_STAT_IRQ_FLAG;      /* clear interrupt flag */



    uint8_t i;



    //-------------------- 15 DCO block ------------------------------------------

    DCO=0;

    for (i=0;i<15;i++) {

    	DCOPH[i] += FREQ[i];              //Add freq to phaseacc's

    	DCO += waveform[(DCOPH[i]>>15)&255];  //Add DCO's to output

    }

    DCO = DCO<<4;

    //---------------------------------------------------------------------------



    //---------------- DCF block ---------------------------------------

    //C implementation for a 4pole lowpass DCF with resonance:



    vi=DCO;

    for (i=0;i<8;i++) {

    t[i] = ((t[i] * (65536 - CFREQ)) + (t[i+1] * CFREQ))>>16;  //+3dB per iteration

    }

    t[8] = vi-((t[0]*RESONANCE)>>16);  //resonance feedback

    DCF=t[0];

    //-----------------------------------------------------------------



    //--------------------- ENV block ---------------------------------

    if (!envstat--) {

    envstat=1024;

    if (TRIG) {



    	if (state0==1) {

    		volume0 -= DECAY0;

    		if (SUSTAIN0>volume0) {

    			volume0=SUSTAIN0;

    			state0++;

    		}

    	}

    	if (state0==0) {

    		volume0 += ATTACK0;

    		if (volume0>0xFFFF) {

    			volume0=0xFFFF;

    			state0++;

    		}

    	}

    	if (state1==1) {

    		volume1 -= DECAY1;

    		if (SUSTAIN1>volume1) {

    			volume1=SUSTAIN1;

    			state1++;

    		}

    	}

    	if (state1==0) {

    		volume1 += ATTACK1;

    		if (volume1>0xFFFF) {

    			volume1=0xFFFF;

    			state1++;

    		}

    	}

    }

    if (!TRIG) {

    		volume0 -= RELEASE0;

    		if (volume0<0) {

    			volume0=0;

    		}

    		volume1 -= RELEASE1;

    		if (volume1<0) {

    			volume1=0;

    		}



    }

    //-------------------- LFO block ----------------------------------

    lfocounter+=LFORATE;

    int8_t TRILFO=(lfocounter&127);

    if (lfocounter&128) TRILFO=127-(lfocounter&127);

    TRILFO=127-(TRILFO<<1);

    if (LFOWAVE<64) {

    	CFREQ=(int32_t)((TRILFO*LFOMOD)+((volume1>>8)*ENVMOD));

    	CFREQ=CFREQ+CUTOFF;

    	if (CFREQ>65535) CFREQ=65535;

    	if (CFREQ<0) CFREQ=0;

    }

    else {

    	if (lfocounter&128) {

    		CFREQ=(int32_t)((shrandom*LFOMOD)+((volume1>>8)*ENVMOD));

    		CFREQ=CFREQ+CUTOFF;

    		if (CFREQ>65535) CFREQ=65535;

    		if (CFREQ<0) CFREQ=0;

    		lfocounter=0;

    	}

    }



	}

    //-----------------------------------------------------------------



    ENV=(volume0*DCF)>>16;



    //-----------------------------------------------------------------



    ENV=(MASTERVOL*ENV)>>16;

    



    DACH=(ENV>>8);

    DACL=(ENV&0xFF);

    

	LPC_SCT->MATCHREL[1].L  = DACL;

	LPC_SCT->MATCHREL[1].H  = DACH;

  }



  return;

}



void handleMIDICC(uint8_t CC,uint8_t value) {

	uint8_t i;





	/*

	 MIDI CCs:



	 CUTOFF       = CC#74

	 RESONANCE    = CC#71

	 FILTER A     = CC#82

	 FILTER D     = CC#83

	 FILTER S     = CC#28

	 FILTER R     = CC#29

	 FILTER ENV M = CC#81

	 FILTER LFO M = CC#01



	 WAVEFORM     = CC#76

	 WRAP		      = CC#04

	 RANGE        = CC#21

	 DETUNE       = CC#93

	 OSCENV A     = CC#73

	 OSCENV D     = CC#75

	 OSCENV S     = CC#31

	 OSCENV R     = CC#72



	 MASTERVOL    = CC#07

	 LFORATE      = CC#16

	 LFOWAVE      = CC#20



	 */

	switch(CC) {

	case 74:

		CUTOFF=value<<9;

	break;

	case 71:

		RESONANCE=value<<9;

	break;

	case 82:

		ATTACK1=ENVRATES[value>>2];

	break;

	case 83:

		DECAY1=ENVRATES[value>>2];

	break;

	case 28:

		SUSTAIN1=ENVRATES[value>>2];

	break;

	case 29:

		RELEASE1=ENVRATES[value>>2];

	break;

	case 73:

		ATTACK0=ENVRATES[value>>2];

	break;

	case 75:

		DECAY0=ENVRATES[value>>2];

	break;

	case 31:

		SUSTAIN0=ENVRATES[value>>2];

	break;

	case 72:

		RELEASE0=ENVRATES[value>>2];

	break;

	case 93:

		DETUNE=value;

		for (i=0;i<5;i++) {

		  if (FREQ[i*3]) {

			  FREQ[i*3+1]=FREQ[i*3]+((FREQ[i*3]/50)*DETUNE/127)+((FREQ[i*3]/2)*RANGE/32);

			  FREQ[i*3+2]=FREQ[i*3]-((FREQ[i*3]/50)*DETUNE/127)+((FREQ[i*3]/2)*RANGE/32);

		  }

		}

	break;

	case 21:

		RANGE=value;

		for (i=0;i<5;i++) {

		  if (FREQ[i*3]) {

			  FREQ[i*3+1]=FREQ[i*3]+((FREQ[i*3]/50)*DETUNE/127)+((FREQ[i*3]/2)*RANGE/32);

			  FREQ[i*3+2]=FREQ[i*3]-((FREQ[i*3]/50)*DETUNE/127)+((FREQ[i*3]/2)*RANGE/32);

		  }

		}

	break;

	case 81:

		ENVMOD=value<<1;

	break;

	case 01:

		LFOMOD=value<<1;

	break;

	case 16:

		LFORATE=(value>>1)+1;

	break;

	case 76:

		WAVEFORM=value<<1;

	break;

	case 04:

		WRAP=value<<1;

	break;

	case 20:

		LFOWAVE=value;

	break;

	case 07:

		MASTERVOL=value<<9;

	break;

	}



}



void handleMIDINOTE(uint8_t status,uint8_t note,uint8_t vel) {

	uint8_t i;

	//uint8_t trigflag=0;

	uint32_t freq;

	if ((!vel)&&(status==0x90)) status=0x80;

	if (status==0x80) {

	      for (i=0;i<5;i++) {

	    	  if (OSCNOTES[i]==note) {

	    		  if (!RELEASE0) {

	    		  FREQ[i*3]=0;

	    		  FREQ[i*3+1]=0;

	    		  FREQ[i*3+2]=0;

	    		  }

	    		  OSCNOTES[i]=0;

	    	  }

	    	  //trigflag+=OSCNOTES[i];

	      }

	      if (!(OSCNOTES[0]|OSCNOTES[1]|OSCNOTES[2]|OSCNOTES[3]|OSCNOTES[4])) TRIG=0;

	      return;

	}



	if (status==0x90) {

		if ((!TRIG)&&(RELEASE0)) {

			for (i=0;i<14;i++) {

				FREQ[i]=0;

			}

		}

		i=0;

		while (i<5) {

	      if (!OSCNOTES[i]) {

    		  freq=MIDI2FREQ(note);

    		  FREQ[i*3]=freq;

			  FREQ[i*3+1]=FREQ[i*3]+((FREQ[i*3]/50)*DETUNE/127)+((FREQ[i*3]/2)*RANGE/32);

			  FREQ[i*3+2]=FREQ[i*3]-((FREQ[i*3]/50)*DETUNE/127)+((FREQ[i*3]/2)*RANGE/32);

	    	  OSCNOTES[i]=note;

	    	  if (!TRIG) {

	    		  TRIG=1;

	    		  state0=0;

	    		  state1=0;

	    	  }

	    	  return;

	      }

	      i++;

		}

	}



}



void UART0_IRQHandler(void) {

      uint8_t MIDIRX;

	  while (!(LPC_USART0->STAT & UART_STATUS_TXRDY));

	  MIDIRX = LPC_USART0->RXDATA;



	  /*

	  Handling "Running status"

	  1.Buffer is cleared (ie, set to 0) at power up.

	  2.Buffer stores the status when a Voice Category Status (ie, 0x80 to 0xEF) is received.

	  3.Buffer is cleared when a System Common Category Status (ie, 0xF0 to 0xF7) is received.

	  4.Nothing is done to the buffer when a RealTime Category message is received.

	  5.Any data bytes are ignored when the buffer is 0.

	  */



	  if ((MIDIRX>0xBF)&&(MIDIRX<0xF8)) {

		  MIDIRUNNINGSTATUS=0;

		  MIDISTATE=0;

		  return;

	  }



	  if (MIDIRX>0xF7) return;



	  if (MIDIRX & 0x80) {

		  MIDIRUNNINGSTATUS=MIDIRX;

		  MIDISTATE=1;

		  return;

	  }



	  if (MIDIRX < 0x80) {

	  	  if (!MIDIRUNNINGSTATUS) return;

	  	  if (MIDISTATE==1) {

	  		  MIDINOTE=MIDIRX;

	  		  MIDISTATE++;

	  		  return;

	  	  }

	  	  if (MIDISTATE==2) {

	  		  MIDIVEL=MIDIRX;

	  		  MIDISTATE=1;

	  		  if ((MIDIRUNNINGSTATUS==0x80)||(MIDIRUNNINGSTATUS==0x90)) handleMIDINOTE(MIDIRUNNINGSTATUS,MIDINOTE,MIDIVEL);

	  		  if (MIDIRUNNINGSTATUS==0xB0) handleMIDICC(MIDINOTE,MIDIVEL);



	  		  return;

	  	  }

	  	  }



	  return;

}





void mrtInit(uint32_t delay)

{

  /* Enable clock to MRT and reset the MRT peripheral */

  LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<10);

  LPC_SYSCON->PRESETCTRL &= ~(0x1<<7);

  LPC_SYSCON->PRESETCTRL |= (0x1<<7);



  LPC_MRT->Channel[0].INTVAL = delay;

  LPC_MRT->Channel[0].INTVAL |= 0x1UL<<31;



  LPC_MRT->Channel[0].CTRL = MRT_REPEATED_MODE|MRT_INT_ENA;



  /* Enable the MRT Interrupt */

#if NMI_ENABLED

  NVIC_DisableIRQ( MRT_IRQn );

  NMI_Init( MRT_IRQn );

#else

  NVIC_EnableIRQ(MRT_IRQn);

#endif

  return;

}



int main(void)

{

  /* Initialise the GPIO block */

	  /* Enable AHB clock to the GPIO domain. */

	  LPC_SYSCON->SYSAHBCLKCTRL |=  (1 << 6);

	  LPC_SYSCON->SYSAHBCLKCTRL |=  (1 << 11); //Enable SPI0 clk

	  LPC_SYSCON->PRESETCTRL    &= ~(1 << 10);

	  LPC_SYSCON->PRESETCTRL    |=  (1 << 10);

	  LPC_SYSCON->PRESETCTRL    &= ~(1); //Reset SPI0

	  LPC_SYSCON->PRESETCTRL    |=  (1); //Reset SPI0

      LPC_SWM->PINENABLE0 = 0xffffffffUL; //All 6 GPIO enabled



      LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); // enable the SCT clock

      LPC_SCT->CTRL_L |= ((0 << 5) | (1<<3)); // set pre-scalar, SCT clock, clear counter

      LPC_SCT->CTRL_H |= ((0 << 5) | (1<<3)); // set pre-scalar, SCT clock, clear counter



      sct_fsm_init();

      LPC_SCT->CTRL_L &= ~(1<<2); // unhalt the SCT by clearing bit 2 in CTRL

      LPC_SCT->CTRL_H &= ~(1<<2); // unhalt the SCT by clearing bit 2 in CTRL

      LPC_SWM->PINASSIGN6 = 0x03ffffffUL; /* CTOUT_0 = P0_3*/

      LPC_SWM->PINASSIGN7 = 0x0fffff02UL; /* CTOUT_1 = P0_2*/



      /* Pin Assign 8 bit Configuration */

      /* U0_TXD */

      /* U0_RXD */

      LPC_SWM->PINASSIGN0 = 0xffff0004UL;



      /* Initialise the UART0 block for printf output */

      uart0Init(31250);



      /* Configure the multi-rate timer for 44.1K ticks */

      //mrtInit(__SYSTEM_CLOCK/42188);

      mrtInit(48000000/44100);



      uint16_t i;

      for (i=0;i<256;i++) {

    	waveform[i]=(i-127);

      }

      for (i=0;i<5;i++) {

        FREQ[i] = 0;

      }

      i=0;

	  int8_t TRI;

	  int8_t SQR;

	  int8_t SAW;

	  int16_t SUM;

      while(1) {

    	  for (i=0;i<256;i++) {

    	    SUM=0;

...

This file has been truncated, please download it to see its full contents.

Credits

Jan Ostman
34 projects • 167 followers
I'm an embeddeds wizard that can turn any pile of electronic junk to something really great. Mc Gyver style.
Contact

Comments

Please log in or sign up to comment.